eclair snapshot
diff --git a/Android.mk b/Android.mk
index a570324..2632f47 100644
--- a/Android.mk
+++ b/Android.mk
@@ -10,8 +10,6 @@
LOCAL_PACKAGE_NAME := Contacts
LOCAL_CERTIFICATE := shared
-LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client
-
include $(BUILD_PACKAGE)
# Use the folloing include to make our test apk.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9ff4b4b..9d6ff4b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -4,9 +4,9 @@
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.
@@ -15,9 +15,10 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.contacts"
- android:sharedUserId="android.uid.shared"
+ package="com.android.contacts"
+ android:sharedUserId="android.uid.shared"
>
+
<uses-permission android:name="android.permission.CALL_PRIVILEGED" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
@@ -27,6 +28,8 @@
<uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.mail" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.USE_CREDENTIALS" />
+ <uses-permission android:name="android.permission.VIBRATE" />
<application
android:label="@string/contactsList"
@@ -60,7 +63,7 @@
<!-- Tab container for TwelveKeyDialer and RecentCallsList -->
<activity android:name="DialtactsActivity"
android:label="@string/launcherDialer"
- android:theme="@android:style/Theme.NoTitleBar"
+ android:theme="@style/DialtactsTheme"
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:icon="@drawable/ic_launcher_phone"
@@ -108,8 +111,8 @@
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
-
- <!-- An empty activity that presents the DialtactActivity's Contacts tab -->
+
+ <!-- Tab container for Activity Stream and Contacts -->
<activity-alias android:name="DialtactsContactsEntryActivity"
android:targetActivity="DialtactsActivity"
android:label="@string/contactsList"
@@ -119,14 +122,16 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="vnd.android.cursor.dir/person" />
+ <data android:mimeType="vnd.android.cursor.dir/person" android:host="contacts" />
+ <data android:mimeType="vnd.android.cursor.dir/contact" android:host="com.android.contacts" />
</intent-filter>
-
+
<intent-filter>
<action android:name="com.android.contacts.action.FILTER_CONTACTS" />
<category android:name="android.intent.category.DEFAULT" />
@@ -136,15 +141,13 @@
<!-- An empty activity that presents the DialtactActivity's Favorites tab -->
<activity-alias android:name="DialtactsFavoritesEntryActivity"
android:targetActivity="DialtactsActivity"
- android:label="@string/strequentList"
- android:icon="@drawable/ic_launcher_contacts"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity-alias>
-
+
<!-- The actual list of contacts, usually embedded in ContactsActivity -->
<activity android:name="ContactsListActivity"
android:label="@string/contactsList"
@@ -179,7 +182,7 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.TAB" />
</intent-filter>
-
+
<intent-filter android:label="@string/frequentList">
<action android:name="com.android.contacts.action.LIST_FREQUENT" />
<category android:name="android.intent.category.DEFAULT" />
@@ -196,29 +199,30 @@
<action android:name="android.intent.action.INSERT_OR_EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/person" />
+ <data android:mimeType="vnd.android.cursor.item/contact" />
+ <data android:mimeType="vnd.android.cursor.item/raw_contact" />
</intent-filter>
-<!--
- <intent-filter android:label="Add To Contacts">
- <action android:name="com.android.contacts.action.ADD_CONTACT" />
- <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
- <data android:scheme="mailto" />
- <data android:scheme="tel" />
- </intent-filter>
--->
+
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="vnd.android.cursor.dir/person" />
- <data android:mimeType="vnd.android.cursor.dir/phone" />
- <data android:mimeType="vnd.android.cursor.dir/postal-address" />
+ <data android:mimeType="vnd.android.cursor.dir/contact" android:host="com.android.contacts" />
+ <data android:mimeType="vnd.android.cursor.dir/person" android:host="contacts" />
+ <data android:mimeType="vnd.android.cursor.dir/phone_v2" android:host="com.android.contacts" />
+ <data android:mimeType="vnd.android.cursor.dir/phone" android:host="contacts" />
+ <data android:mimeType="vnd.android.cursor.dir/postal-address_v2" android:host="com.android.contacts" />
+ <data android:mimeType="vnd.android.cursor.dir/postal-address" android:host="contacts" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="vnd.android.cursor.item/person" />
- <data android:mimeType="vnd.android.cursor.item/phone" />
- <data android:mimeType="vnd.android.cursor.item/postal-address" />
+ <data android:mimeType="vnd.android.cursor.item/contact" android:host="com.android.contacts" />
+ <data android:mimeType="vnd.android.cursor.item/person" android:host="contacts" />
+ <data android:mimeType="vnd.android.cursor.item/phone_v2" android:host="com.android.contacts" />
+ <data android:mimeType="vnd.android.cursor.item/phone" android:host="contacts" />
+ <data android:mimeType="vnd.android.cursor.item/postal-address_v2" android:host="com.android.contacts" />
+ <data android:mimeType="vnd.android.cursor.item/postal-address" android:host="contacts" />
</intent-filter>
<intent-filter>
@@ -231,13 +235,46 @@
/>
</activity>
- <activity android:name="ShowOrCreateActivity"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <!-- An activity for joining contacts -->
+ <activity android:name="ContactsListActivity$JoinContactActivity"
+ android:theme="@style/TallTitleBarTheme"
+ android:clearTaskOnLaunch="true"
+ >
+ <intent-filter>
+ <action android:name="com.android.contacts.action.JOIN_AGGREGATE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+
+ <!-- Used to select display and sync groups -->
+ <activity android:name=".ui.DisplayGroupsActivity" android:label="@string/displayGroups" />
+
+ <activity
+ android:name=".ui.ShowOrCreateActivity"
+ android:theme="@style/FullyTranslucent">
+
<intent-filter>
<action android:name="com.android.contacts.action.SHOW_OR_CREATE_CONTACT" />
+ <category android:name="android.intent.category.DEFAULT" />
<data android:scheme="mailto" />
<data android:scheme="tel" />
+ </intent-filter>
+ </activity>
+
+ <!-- Used to show QuickContact window over a translucent activity, which is a
+ temporary hack until we add better framework support. -->
+ <activity
+ android:name=".ui.QuickContactActivity"
+ android:theme="@style/FullyTranslucent.QuickContact"
+ android:launchMode="singleTop"
+ android:excludeFromRecents="true"
+ android:taskAffinity="android.task.quickcontact">
+
+ <intent-filter>
+ <action android:name="com.android.contacts.action.QUICK_CONTACT" />
<category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="vnd.android.cursor.item/contact" android:host="com.android.contacts" />
</intent-filter>
</activity>
@@ -256,7 +293,7 @@
<activity-alias android:name="alias.DialShortcut"
android:targetActivity="ContactsListActivity"
android:label="@string/shortcutDialContact"
- android:icon="@drawable/ic_launcher_shortcut_contact">
+ android:icon="@drawable/ic_launcher_shortcut_directdial">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
@@ -268,7 +305,7 @@
<activity-alias android:name="alias.MessageShortcut"
android:targetActivity="ContactsListActivity"
android:label="@string/shortcutMessageContact"
- android:icon="@drawable/ic_launcher_shortcut_contact">
+ android:icon="@drawable/ic_launcher_shortcut_directmessage">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
@@ -291,27 +328,54 @@
<!-- Views the details of a single contact -->
<activity android:name="ViewContactActivity"
android:label="@string/viewContactTitle"
- android:theme="@style/TallTitleBarTheme"
- >
+ android:theme="@style/TallTitleBarTheme">
+
<intent-filter android:label="@string/viewContactDesription">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="vnd.android.cursor.item/person" />
+ <data android:mimeType="vnd.android.cursor.item/person" android:host="contacts" />
+ <data android:mimeType="vnd.android.cursor.item/contact" android:host="com.android.contacts" />
+ <data android:mimeType="vnd.android.cursor.item/raw_contact" android:host="com.android.contacts" />
</intent-filter>
</activity>
- <!-- Edits the details of a single contact -->
- <activity android:name="EditContactActivity"
- android:windowSoftInputMode="stateVisible|adjustResize">
+ <!-- Edit or insert details for a contact -->
+ <activity
+ android:name=".ui.EditContactActivity"
+ android:label="@string/editContactDescription"
+ android:windowSoftInputMode="stateHidden|adjustResize">
+
<intent-filter android:label="@string/editContactDescription">
<action android:name="android.intent.action.EDIT" />
<category android:name="android.intent.category.DEFAULT" />
- <data android:mimeType="vnd.android.cursor.item/person" />
+ <data android:mimeType="vnd.android.cursor.item/person" android:host="contacts" />
+ <data android:mimeType="vnd.android.cursor.item/contact" android:host="com.android.contacts" />
+ <data android:mimeType="vnd.android.cursor.item/raw_contact" android:host="com.android.contacts" />
</intent-filter>
+
<intent-filter android:label="@string/insertContactDescription">
<action android:name="android.intent.action.INSERT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/person" />
+ <data android:mimeType="vnd.android.cursor.dir/contact" />
+ <data android:mimeType="vnd.android.cursor.dir/raw_contact" />
+ </intent-filter>
+
+ </activity>
+
+ <!-- Stub service used to keep our process alive long enough for
+ background threads to finish their operations. -->
+ <service
+ android:name=".util.EmptyService"
+ android:exported="false" />
+
+ <!-- Views the details of a single contact -->
+ <activity android:name="ContactOptionsActivity"
+ android:label="@string/contactOptionsTitle"
+ >
+ <intent-filter>
+ <action android:name="android.intent.action.EDIT" />
+ <category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
@@ -325,15 +389,10 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
/>
- </activity>
-
- <!-- Activity used to select the groups that should be synced -->
- <activity android:name="ContactsGroupSyncSelector"
- android:label="@string/seclectSyncGroups_title"
- />
+ </activity>
<!-- Makes .ContactsListActivity the search target for any activity in Contacts -->
- <meta-data android:name="android.app.default_searchable"
+ <meta-data android:name="android.app.default_searchable"
android:value=".ContactsListActivity" />
@@ -371,8 +430,7 @@
<activity android:name=".ImportVCardActivity"
android:theme="@style/BackgroundOnly" />
+ <activity android:name=".ExportVCardActivity"
+ android:theme="@style/BackgroundOnly" />
</application>
</manifest>
-
-
-
diff --git a/res/anim/dummy_animation.xml b/res/anim/dummy_animation.xml
new file mode 100644
index 0000000..5b42f24
--- /dev/null
+++ b/res/anim/dummy_animation.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<translate
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="0"
+ android:toXDelta="0"
+ android:duration="@android:integer/config_shortAnimTime" />
diff --git a/res/anim/quickcontact.xml b/res/anim/quickcontact.xml
new file mode 100644
index 0000000..6fd1a27
--- /dev/null
+++ b/res/anim/quickcontact.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<translate
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="100%p"
+ android:toXDelta="0"
+ android:duration="400" />
diff --git a/res/anim/quickcontact_above_enter.xml b/res/anim/quickcontact_above_enter.xml
new file mode 100644
index 0000000..dc2d053
--- /dev/null
+++ b/res/anim/quickcontact_above_enter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <scale android:interpolator="@android:anim/decelerate_interpolator"
+ android:fromXScale="0.75" android:toXScale="1.0"
+ android:fromYScale="0.75" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="100%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@android:anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/res/anim/quickcontact_above_exit.xml b/res/anim/quickcontact_above_exit.xml
new file mode 100644
index 0000000..dd34f87
--- /dev/null
+++ b/res/anim/quickcontact_above_exit.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/accelerate_interpolator">
+ <scale android:fromXScale="1.0" android:toXScale=".5"
+ android:fromYScale="1.0" android:toYScale=".5"
+ android:pivotX="50%" android:pivotY="100%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/res/anim/quickcontact_below_enter.xml b/res/anim/quickcontact_below_enter.xml
new file mode 100644
index 0000000..9a1a577
--- /dev/null
+++ b/res/anim/quickcontact_below_enter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <scale android:interpolator="@android:anim/decelerate_interpolator"
+ android:fromXScale="0.75" android:toXScale="1.0"
+ android:fromYScale="0.75" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="0%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@android:anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/res/anim/quickcontact_below_exit.xml b/res/anim/quickcontact_below_exit.xml
new file mode 100644
index 0000000..7587c7a
--- /dev/null
+++ b/res/anim/quickcontact_below_exit.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/accelerate_interpolator">
+ <scale android:fromXScale="1.0" android:toXScale=".5"
+ android:fromYScale="1.0" android:toYScale=".5"
+ android:pivotX="50%" android:pivotY="0%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/res/color-finger/dialer_button_text.xml b/res/color-finger/dialer_button_text.xml
index 9e71988..585906e 100644
--- a/res/color-finger/dialer_button_text.xml
+++ b/res/color-finger/dialer_button_text.xml
@@ -4,9 +4,9 @@
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.
@@ -17,7 +17,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="#000"/>
- <item android:state_focused="true" android:color="#000"/>
+ <item android:state_focused="true" android:color="#FFF"/>
<item android:color="#FFF"/> <!-- not selected -->
</selector>
diff --git a/res/drawable-finger/dial_num_1.xml b/res/color-finger/kind_title.xml
similarity index 68%
copy from res/drawable-finger/dial_num_1.xml
copy to res/color-finger/kind_title.xml
index 48737b2..7489f75 100644
--- a/res/drawable-finger/dial_num_1.xml
+++ b/res/color-finger/kind_title.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -15,11 +15,5 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/dial_num_1_blk" />
- <item android:state_focused="true"
- android:drawable="@drawable/dial_num_1_blk" />
- <item
- android:drawable="@drawable/dial_num_1_wht" />
+ <item android:color="@*android:color/bright_foreground_dark" />
</selector>
-
diff --git a/res/drawable-finger/dial_num_1.xml b/res/color-finger/tab_indicator_text.xml
similarity index 73%
copy from res/drawable-finger/dial_num_1.xml
copy to res/color-finger/tab_indicator_text.xml
index 48737b2..50ca824 100644
--- a/res/drawable-finger/dial_num_1.xml
+++ b/res/color-finger/tab_indicator_text.xml
@@ -4,9 +4,9 @@
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.
@@ -15,11 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/dial_num_1_blk" />
- <item android:state_focused="true"
- android:drawable="@drawable/dial_num_1_blk" />
- <item
- android:drawable="@drawable/dial_num_1_wht" />
+ <item android:state_selected="true" android:color="@*android:color/dim_foreground_dark_inverse"/>
+ <item android:color="@*android:color/dim_foreground_dark"/> <!-- not selected -->
</selector>
-
diff --git a/res/drawable-finger/btn_dial.xml b/res/drawable-finger/btn_dial.xml
index 4dfcd64..22a785a 100644
--- a/res/drawable-finger/btn_dial.xml
+++ b/res/drawable-finger/btn_dial.xml
@@ -14,6 +14,9 @@
limitations under the License.
-->
+<!-- Background resource for digit buttons in the various dialpads
+ used by the Contacts app (see dialpad.xml).
+ -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/btn_dial_pressed" />
diff --git a/res/drawable-finger/btn_dial_action.xml b/res/drawable-finger/btn_dial_action.xml
new file mode 100644
index 0000000..9ffb31b
--- /dev/null
+++ b/res/drawable-finger/btn_dial_action.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<!-- Background resource for dial button for the various 12 key dialers. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Disabled views -->
+ <item android:state_focused="true" android:state_enabled="false"
+ android:drawable="@drawable/btn_dial_action_middle_disable_focused" />
+ <item android:state_enabled="false"
+ android:drawable="@drawable/btn_dial_action_middle_disable" />
+
+ <!-- Enabled views -->
+ <item android:state_pressed="true" android:state_enabled="true"
+ android:drawable="@drawable/btn_dial_action_middle_pressed" />
+ <item android:state_focused="true" android:state_enabled="true"
+ android:drawable="@drawable/btn_dial_action_middle_selected" />
+ <item android:state_enabled="true"
+ android:drawable="@drawable/btn_dial_action_middle_normal" />
+</selector>
diff --git a/res/drawable-finger/btn_dial_delete.xml b/res/drawable-finger/btn_dial_delete.xml
index 235554d..b8c672d 100644
--- a/res/drawable-finger/btn_dial_delete.xml
+++ b/res/drawable-finger/btn_dial_delete.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -14,12 +14,20 @@
limitations under the License.
-->
+<!-- Background resource for backspace button for the various 12 key dialers. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/btn_dial_delete_pressed" />
- <item android:state_focused="true"
- android:drawable="@drawable/btn_dial_delete_selected" />
- <item
- android:drawable="@drawable/btn_dial_delete_normal" />
+ <!-- Disabled views -->
+ <item android:state_focused="true" android:state_enabled="false"
+ android:drawable="@drawable/btn_dial_action_right_disable_focused" />
+ <item android:state_enabled="false"
+ android:drawable="@drawable/btn_dial_action_right_disable" />
+
+ <!-- Enabled views -->
+ <item android:state_pressed="true" android:state_enabled="true"
+ android:drawable="@drawable/btn_dial_action_right_pressed" />
+ <item android:state_focused="true" android:state_enabled="true"
+ android:drawable="@drawable/btn_dial_action_right_selected" />
+ <item android:state_enabled="true"
+ android:drawable="@drawable/btn_dial_action_right_normal" />
</selector>
diff --git a/res/drawable-finger/btn_dial_delete_activated.9.png b/res/drawable-finger/btn_dial_delete_activated.9.png
deleted file mode 100644
index 453a368..0000000
--- a/res/drawable-finger/btn_dial_delete_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_delete_active.xml b/res/drawable-finger/btn_dial_delete_active.xml
deleted file mode 100644
index 3403f34..0000000
--- a/res/drawable-finger/btn_dial_delete_active.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/btn_dial_delete_pressed" />
- <item android:state_focused="true"
- android:drawable="@drawable/btn_dial_delete_selected" />
- <item
- android:drawable="@drawable/btn_dial_delete_activated" />
-</selector>
-
diff --git a/res/drawable-finger/btn_dial_delete_normal.9.png b/res/drawable-finger/btn_dial_delete_normal.9.png
deleted file mode 100644
index 9da1cff..0000000
--- a/res/drawable-finger/btn_dial_delete_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_delete_pressed.9.png b/res/drawable-finger/btn_dial_delete_pressed.9.png
deleted file mode 100644
index 5bbc20d..0000000
--- a/res/drawable-finger/btn_dial_delete_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_delete_selected.9.png b/res/drawable-finger/btn_dial_delete_selected.9.png
deleted file mode 100644
index d959768..0000000
--- a/res/drawable-finger/btn_dial_delete_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_normal.png b/res/drawable-finger/btn_dial_normal.png
deleted file mode 100644
index ff8796b..0000000
--- a/res/drawable-finger/btn_dial_normal.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_pressed.png b/res/drawable-finger/btn_dial_pressed.png
deleted file mode 100644
index 3c198c4..0000000
--- a/res/drawable-finger/btn_dial_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_selected.png b/res/drawable-finger/btn_dial_selected.png
deleted file mode 100644
index 8ca2b0d..0000000
--- a/res/drawable-finger/btn_dial_selected.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_textfield.xml b/res/drawable-finger/btn_dial_textfield.xml
index 4eabf18..109f6ae 100644
--- a/res/drawable-finger/btn_dial_textfield.xml
+++ b/res/drawable-finger/btn_dial_textfield.xml
@@ -15,10 +15,10 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
+ <item android:state_pressed="true"
android:drawable="@drawable/btn_dial_textfield_pressed" />
<item android:state_focused="true"
- android:drawable="@drawable/btn_dial_textfield_selected" />
+ android:drawable="@drawable/btn_dial_textfield_normal" />
<item
android:drawable="@drawable/btn_dial_textfield_normal" />
</selector>
diff --git a/res/drawable-finger/btn_dial_textfield_activated.9.png b/res/drawable-finger/btn_dial_textfield_activated.9.png
deleted file mode 100644
index 4c34576..0000000
--- a/res/drawable-finger/btn_dial_textfield_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_textfield_active.xml b/res/drawable-finger/btn_dial_textfield_active.xml
index 18b84c6..246d543 100644
--- a/res/drawable-finger/btn_dial_textfield_active.xml
+++ b/res/drawable-finger/btn_dial_textfield_active.xml
@@ -15,10 +15,10 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
+ <item android:state_pressed="true"
android:drawable="@drawable/btn_dial_textfield_pressed" />
<item android:state_focused="true"
- android:drawable="@drawable/btn_dial_textfield_selected" />
+ android:drawable="@drawable/btn_dial_textfield_activated" />
<item
android:drawable="@drawable/btn_dial_textfield_activated" />
</selector>
diff --git a/res/drawable-finger/btn_dial_textfield_normal.9.png b/res/drawable-finger/btn_dial_textfield_normal.9.png
deleted file mode 100644
index 40ab866..0000000
--- a/res/drawable-finger/btn_dial_textfield_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_textfield_pressed.9.png b/res/drawable-finger/btn_dial_textfield_pressed.9.png
deleted file mode 100644
index 0087327..0000000
--- a/res/drawable-finger/btn_dial_textfield_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_textfield_selected.9.png b/res/drawable-finger/btn_dial_textfield_selected.9.png
deleted file mode 100644
index 63fceaa..0000000
--- a/res/drawable-finger/btn_dial_textfield_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/btn_dial_voicemail.xml b/res/drawable-finger/btn_dial_voicemail.xml
new file mode 100644
index 0000000..8669f0f
--- /dev/null
+++ b/res/drawable-finger/btn_dial_voicemail.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<!-- Background resource for dial voicemail button for the various 12 key dialers. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Disabled views -->
+ <item android:state_focused="true" android:state_enabled="false"
+ android:drawable="@drawable/btn_dial_action_left_disable_focused" />
+ <item android:state_enabled="false"
+ android:drawable="@drawable/btn_dial_action_left_disable" />
+
+ <!-- Enabled views -->
+ <item android:state_pressed="true" android:state_enabled="true"
+ android:drawable="@drawable/btn_dial_action_left_pressed" />
+ <item android:state_focused="true" android:state_enabled="true"
+ android:drawable="@drawable/btn_dial_action_left_selected" />
+ <item android:state_enabled="true"
+ android:drawable="@drawable/btn_dial_action_left_normal" />
+</selector>
diff --git a/res/drawable-finger/dial_num_0_blk.png b/res/drawable-finger/dial_num_0_blk.png
deleted file mode 100644
index a10c601..0000000
--- a/res/drawable-finger/dial_num_0_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_0_wht.png b/res/drawable-finger/dial_num_0_wht.png
deleted file mode 100644
index 2de90a1..0000000
--- a/res/drawable-finger/dial_num_0_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_1_blk.png b/res/drawable-finger/dial_num_1_blk.png
deleted file mode 100644
index 822f9ca..0000000
--- a/res/drawable-finger/dial_num_1_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_1.xml b/res/drawable-finger/dial_num_1_no_vm.xml
similarity index 78%
rename from res/drawable-finger/dial_num_1.xml
rename to res/drawable-finger/dial_num_1_no_vm.xml
index 48737b2..daa4613 100644
--- a/res/drawable-finger/dial_num_1.xml
+++ b/res/drawable-finger/dial_num_1_no_vm.xml
@@ -15,11 +15,11 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/dial_num_1_blk" />
+ <item android:state_pressed="true"
+ android:drawable="@drawable/dial_num_1_no_vm_blk" />
<item android:state_focused="true"
- android:drawable="@drawable/dial_num_1_blk" />
+ android:drawable="@drawable/dial_num_1_no_vm_blk" />
<item
- android:drawable="@drawable/dial_num_1_wht" />
+ android:drawable="@drawable/dial_num_1_no_vm_wht" />
</selector>
diff --git a/res/drawable-finger/dial_num_1_wht.png b/res/drawable-finger/dial_num_1_wht.png
deleted file mode 100644
index e488beb..0000000
--- a/res/drawable-finger/dial_num_1_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_2_blk.png b/res/drawable-finger/dial_num_2_blk.png
deleted file mode 100644
index 539c301..0000000
--- a/res/drawable-finger/dial_num_2_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_2_wht.png b/res/drawable-finger/dial_num_2_wht.png
deleted file mode 100644
index cd1ae8d..0000000
--- a/res/drawable-finger/dial_num_2_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_3_blk.png b/res/drawable-finger/dial_num_3_blk.png
deleted file mode 100644
index dc70f33..0000000
--- a/res/drawable-finger/dial_num_3_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_3_wht.png b/res/drawable-finger/dial_num_3_wht.png
deleted file mode 100644
index dc7c8e2..0000000
--- a/res/drawable-finger/dial_num_3_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_4_blk.png b/res/drawable-finger/dial_num_4_blk.png
deleted file mode 100644
index 084db44..0000000
--- a/res/drawable-finger/dial_num_4_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_4_wht.png b/res/drawable-finger/dial_num_4_wht.png
deleted file mode 100644
index 44128a1..0000000
--- a/res/drawable-finger/dial_num_4_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_5_blk.png b/res/drawable-finger/dial_num_5_blk.png
deleted file mode 100644
index 0a06f20..0000000
--- a/res/drawable-finger/dial_num_5_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_5_wht.png b/res/drawable-finger/dial_num_5_wht.png
deleted file mode 100644
index fc605b8..0000000
--- a/res/drawable-finger/dial_num_5_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_6_blk.png b/res/drawable-finger/dial_num_6_blk.png
deleted file mode 100644
index 2498d77..0000000
--- a/res/drawable-finger/dial_num_6_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_6_wht.png b/res/drawable-finger/dial_num_6_wht.png
deleted file mode 100644
index 086e8ce..0000000
--- a/res/drawable-finger/dial_num_6_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_7_blk.png b/res/drawable-finger/dial_num_7_blk.png
deleted file mode 100644
index cfb20a7..0000000
--- a/res/drawable-finger/dial_num_7_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_7_wht.png b/res/drawable-finger/dial_num_7_wht.png
deleted file mode 100644
index cb1b097..0000000
--- a/res/drawable-finger/dial_num_7_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_8_blk.png b/res/drawable-finger/dial_num_8_blk.png
deleted file mode 100644
index 845ee68..0000000
--- a/res/drawable-finger/dial_num_8_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_8_wht.png b/res/drawable-finger/dial_num_8_wht.png
deleted file mode 100644
index 1954f10..0000000
--- a/res/drawable-finger/dial_num_8_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_9_blk.png b/res/drawable-finger/dial_num_9_blk.png
deleted file mode 100644
index 752df25..0000000
--- a/res/drawable-finger/dial_num_9_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_9_wht.png b/res/drawable-finger/dial_num_9_wht.png
deleted file mode 100644
index d8b5aa1..0000000
--- a/res/drawable-finger/dial_num_9_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_pound_blk.png b/res/drawable-finger/dial_num_pound_blk.png
deleted file mode 100644
index 4dabda4..0000000
--- a/res/drawable-finger/dial_num_pound_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_pound_wht.png b/res/drawable-finger/dial_num_pound_wht.png
deleted file mode 100644
index f27ae87..0000000
--- a/res/drawable-finger/dial_num_pound_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_star_blk.png b/res/drawable-finger/dial_num_star_blk.png
deleted file mode 100644
index af917ef..0000000
--- a/res/drawable-finger/dial_num_star_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_star_wht.png b/res/drawable-finger/dial_num_star_wht.png
deleted file mode 100644
index ffbd43f..0000000
--- a/res/drawable-finger/dial_num_star_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/divider_vertical_dark.png b/res/drawable-finger/divider_vertical_dark.png
deleted file mode 100644
index dcf850e..0000000
--- a/res/drawable-finger/divider_vertical_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/ic_default_number.png b/res/drawable-finger/ic_default_number.png
deleted file mode 100644
index a27685e..0000000
--- a/res/drawable-finger/ic_default_number.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/ic_delete_phone_number_blk.png b/res/drawable-finger/ic_delete_phone_number_blk.png
deleted file mode 100644
index 2e83d36..0000000
--- a/res/drawable-finger/ic_delete_phone_number_blk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/ic_delete_phone_number_wht.png b/res/drawable-finger/ic_delete_phone_number_wht.png
deleted file mode 100644
index 988bcfd..0000000
--- a/res/drawable-finger/ic_delete_phone_number_wht.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_1.xml b/res/drawable-finger/ic_tab_friends.xml
similarity index 74%
copy from res/drawable-finger/dial_num_1.xml
copy to res/drawable-finger/ic_tab_friends.xml
index 48737b2..58234ae 100644
--- a/res/drawable-finger/dial_num_1.xml
+++ b/res/drawable-finger/ic_tab_friends.xml
@@ -15,11 +15,7 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/dial_num_1_blk" />
- <item android:state_focused="true"
- android:drawable="@drawable/dial_num_1_blk" />
- <item
- android:drawable="@drawable/dial_num_1_wht" />
+ <item android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/ic_tab_selected_friends_list" />
+ <item android:drawable="@drawable/ic_tab_unselected_friends_list" />
</selector>
diff --git a/res/drawable-finger/ic_tab_selected_contacts.png b/res/drawable-finger/ic_tab_selected_contacts.png
deleted file mode 100644
index 16c4a91..0000000
--- a/res/drawable-finger/ic_tab_selected_contacts.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/ic_tab_selected_dialer.png b/res/drawable-finger/ic_tab_selected_dialer.png
deleted file mode 100644
index cb715ed..0000000
--- a/res/drawable-finger/ic_tab_selected_dialer.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/ic_tab_selected_recent.png b/res/drawable-finger/ic_tab_selected_recent.png
deleted file mode 100644
index bdbfc41..0000000
--- a/res/drawable-finger/ic_tab_selected_recent.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/ic_tab_selected_starred.png b/res/drawable-finger/ic_tab_selected_starred.png
deleted file mode 100644
index 1b884cb..0000000
--- a/res/drawable-finger/ic_tab_selected_starred.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/ic_tab_unselected_contacts.png b/res/drawable-finger/ic_tab_unselected_contacts.png
deleted file mode 100644
index 7b5b84f..0000000
--- a/res/drawable-finger/ic_tab_unselected_contacts.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/ic_tab_unselected_dialer.png b/res/drawable-finger/ic_tab_unselected_dialer.png
deleted file mode 100644
index dc3c5d8..0000000
--- a/res/drawable-finger/ic_tab_unselected_dialer.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/ic_tab_unselected_recent.png b/res/drawable-finger/ic_tab_unselected_recent.png
deleted file mode 100644
index 712e405..0000000
--- a/res/drawable-finger/ic_tab_unselected_recent.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/ic_tab_unselected_starred.png b/res/drawable-finger/ic_tab_unselected_starred.png
deleted file mode 100644
index 8eaccb8..0000000
--- a/res/drawable-finger/ic_tab_unselected_starred.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/dial_num_1.xml b/res/drawable-finger/quickcontact_disambig_checkbox.xml
similarity index 69%
copy from res/drawable-finger/dial_num_1.xml
copy to res/drawable-finger/quickcontact_disambig_checkbox.xml
index 48737b2..4add69c 100644
--- a/res/drawable-finger/dial_num_1.xml
+++ b/res/drawable-finger/quickcontact_disambig_checkbox.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -14,12 +14,12 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/dial_num_1_blk" />
- <item android:state_focused="true"
- android:drawable="@drawable/dial_num_1_blk" />
- <item
- android:drawable="@drawable/dial_num_1_wht" />
-</selector>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:dither="true">
+ <item android:state_checked="true"
+ android:drawable="@drawable/quickcontact_disambig_checkbox_on" />
+ <item
+ android:drawable="@drawable/quickcontact_disambig_checkbox_off" />
+
+</selector>
diff --git a/res/drawable-finger/quickcontact_slider_btn.xml b/res/drawable-finger/quickcontact_slider_btn.xml
new file mode 100644
index 0000000..a1be8f4
--- /dev/null
+++ b/res/drawable-finger/quickcontact_slider_btn.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:dither="true">
+
+ <item android:state_checked="true"
+ android:drawable="@drawable/quickcontact_slider_btn_on" />
+ <item android:state_window_focused="false"
+ android:drawable="@drawable/quickcontact_slider_btn_normal" />
+ <item android:state_pressed="true"
+ android:drawable="@drawable/quickcontact_slider_btn_pressed" />
+ <item android:state_focused="true"
+ android:drawable="@drawable/quickcontact_slider_btn_selected" />
+ <item
+ android:drawable="@drawable/quickcontact_slider_btn_normal" />
+
+</selector>
diff --git a/res/drawable-finger/sym_action_sms.png b/res/drawable-finger/sym_action_sms.png
deleted file mode 100644
index e0ce4bb..0000000
--- a/res/drawable-finger/sym_action_sms.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-finger/tab_bottom.xml b/res/drawable-finger/tab_bottom.xml
new file mode 100644
index 0000000..96f1a24
--- /dev/null
+++ b/res/drawable-finger/tab_bottom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!--
+ <item android:state_pressed="true" android:drawable="@drawable/tab_pressed_bottom"/>
+ <item android:state_focused="false" android:drawable="@drawable/tab_selected_bottom"/>
+ <item android:state_focused="true" android:drawable="@drawable/tab_focused_bottom"/>
+ -->
+
+ <item
+ android:state_focused="false"
+ android:state_selected="true"
+ android:state_pressed="false"
+ android:drawable="@drawable/tab_selected_bottom" />
+
+ <!-- Focused states -->
+ <item
+ android:state_focused="true"
+ android:state_selected="true"
+ android:state_pressed="false"
+ android:drawable="@drawable/tab_focused_bottom" />
+
+ <!-- Pressed -->
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/tab_pressed_bottom" />
+</selector>
\ No newline at end of file
diff --git a/res/drawable-finger/tab_indicator_bg.xml b/res/drawable-finger/tab_indicator_bg.xml
new file mode 100644
index 0000000..fb54954
--- /dev/null
+++ b/res/drawable-finger/tab_indicator_bg.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Non focused states -->
+ <item
+ android:state_focused="false"
+ android:state_selected="false"
+ android:state_pressed="false"
+ android:drawable="@drawable/tab_unselected" />
+ <item
+ android:state_focused="false"
+ android:state_selected="true"
+ android:state_pressed="false"
+ android:drawable="@drawable/tab_selected" />
+
+ <!-- Focused states -->
+ <item
+ android:state_focused="true"
+ android:state_selected="true"
+ android:state_pressed="false"
+ android:drawable="@drawable/tab_focused" />
+
+ <!-- Pressed -->
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/tab_pressed" />
+
+</selector>
\ No newline at end of file
diff --git a/res/drawable-hdpi-finger/badge_action_call.png b/res/drawable-hdpi-finger/badge_action_call.png
new file mode 100755
index 0000000..105f7d0
--- /dev/null
+++ b/res/drawable-hdpi-finger/badge_action_call.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/badge_action_sms.png b/res/drawable-hdpi-finger/badge_action_sms.png
new file mode 100755
index 0000000..a7862f6
--- /dev/null
+++ b/res/drawable-hdpi-finger/badge_action_sms.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_circle_disable.png b/res/drawable-hdpi-finger/btn_circle_disable.png
new file mode 100755
index 0000000..ae063b5
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_circle_disable.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_circle_disable_focused.png b/res/drawable-hdpi-finger/btn_circle_disable_focused.png
new file mode 100755
index 0000000..7a5d4fe
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_circle_disable_focused.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_circle_normal.png b/res/drawable-hdpi-finger/btn_circle_normal.png
new file mode 100755
index 0000000..5eda668
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_circle_normal.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_circle_pressed.png b/res/drawable-hdpi-finger/btn_circle_pressed.png
new file mode 100755
index 0000000..88848ba
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_circle_pressed.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_circle_selected.png b/res/drawable-hdpi-finger/btn_circle_selected.png
new file mode 100755
index 0000000..7469070
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_circle_selected.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_left_disable.9.png b/res/drawable-hdpi-finger/btn_dial_action_left_disable.9.png
new file mode 100644
index 0000000..7ba8672
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_left_disable.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_left_disable_focused.9.png b/res/drawable-hdpi-finger/btn_dial_action_left_disable_focused.9.png
new file mode 100644
index 0000000..b4300b6
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_left_disable_focused.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_left_normal.9.png b/res/drawable-hdpi-finger/btn_dial_action_left_normal.9.png
new file mode 100644
index 0000000..7ba8672
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_left_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_left_pressed.9.png b/res/drawable-hdpi-finger/btn_dial_action_left_pressed.9.png
new file mode 100644
index 0000000..1dc40b7
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_left_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_left_selected.9.png b/res/drawable-hdpi-finger/btn_dial_action_left_selected.9.png
new file mode 100644
index 0000000..4f6c7cf
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_left_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_middle_disable.9.png b/res/drawable-hdpi-finger/btn_dial_action_middle_disable.9.png
new file mode 100644
index 0000000..0a6cd66
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_middle_disable.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_middle_disable_focused.9.png b/res/drawable-hdpi-finger/btn_dial_action_middle_disable_focused.9.png
new file mode 100644
index 0000000..b28176f
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_middle_disable_focused.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_middle_normal.9.png b/res/drawable-hdpi-finger/btn_dial_action_middle_normal.9.png
new file mode 100644
index 0000000..0a6cd66
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_middle_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_middle_pressed.9.png b/res/drawable-hdpi-finger/btn_dial_action_middle_pressed.9.png
new file mode 100644
index 0000000..58f187d
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_middle_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_middle_selected.9.png b/res/drawable-hdpi-finger/btn_dial_action_middle_selected.9.png
new file mode 100644
index 0000000..f201dee
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_middle_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_right_disable.9.png b/res/drawable-hdpi-finger/btn_dial_action_right_disable.9.png
new file mode 100644
index 0000000..6e6fa30
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_right_disable.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_right_disable_focused.9.png b/res/drawable-hdpi-finger/btn_dial_action_right_disable_focused.9.png
new file mode 100644
index 0000000..46a042f
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_right_disable_focused.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_right_normal.9.png b/res/drawable-hdpi-finger/btn_dial_action_right_normal.9.png
new file mode 100644
index 0000000..6e6fa30
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_right_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_right_pressed.9.png b/res/drawable-hdpi-finger/btn_dial_action_right_pressed.9.png
new file mode 100644
index 0000000..d66a509
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_right_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_action_right_selected.9.png b/res/drawable-hdpi-finger/btn_dial_action_right_selected.9.png
new file mode 100644
index 0000000..d2ee98b
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_action_right_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_normal.9.png b/res/drawable-hdpi-finger/btn_dial_normal.9.png
new file mode 100644
index 0000000..5702e47
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_normal_blue.9.png b/res/drawable-hdpi-finger/btn_dial_normal_blue.9.png
new file mode 100644
index 0000000..ddad155
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_normal_blue.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_normal_green.9.png b/res/drawable-hdpi-finger/btn_dial_normal_green.9.png
new file mode 100644
index 0000000..dbb0f97
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_normal_green.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_pressed.9.png b/res/drawable-hdpi-finger/btn_dial_pressed.9.png
new file mode 100644
index 0000000..a5b51d5
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_selected.9.png b/res/drawable-hdpi-finger/btn_dial_selected.9.png
new file mode 100644
index 0000000..b578146
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_textfield_activated.9.png b/res/drawable-hdpi-finger/btn_dial_textfield_activated.9.png
new file mode 100644
index 0000000..c937c5e
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_textfield_activated.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_textfield_normal.9.png b/res/drawable-hdpi-finger/btn_dial_textfield_normal.9.png
new file mode 100644
index 0000000..0c38b39
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_textfield_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_textfield_pressed.9.png b/res/drawable-hdpi-finger/btn_dial_textfield_pressed.9.png
new file mode 100644
index 0000000..22d8235
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_textfield_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/btn_dial_textfield_selected.9.png b/res/drawable-hdpi-finger/btn_dial_textfield_selected.9.png
new file mode 100644
index 0000000..1fe4dfc
--- /dev/null
+++ b/res/drawable-hdpi-finger/btn_dial_textfield_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/contact_picture_border_highlight.9.png b/res/drawable-hdpi-finger/contact_picture_border_highlight.9.png
new file mode 100755
index 0000000..776d614
--- /dev/null
+++ b/res/drawable-hdpi-finger/contact_picture_border_highlight.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/contact_picture_border_in_list.9.png b/res/drawable-hdpi-finger/contact_picture_border_in_list.9.png
new file mode 100755
index 0000000..8166d4f
--- /dev/null
+++ b/res/drawable-hdpi-finger/contact_picture_border_in_list.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/contact_picture_border_normal.9.png b/res/drawable-hdpi-finger/contact_picture_border_normal.9.png
new file mode 100755
index 0000000..be67b1a
--- /dev/null
+++ b/res/drawable-hdpi-finger/contact_picture_border_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/contact_picture_border_pressed.9.png b/res/drawable-hdpi-finger/contact_picture_border_pressed.9.png
new file mode 100755
index 0000000..32fbaa5
--- /dev/null
+++ b/res/drawable-hdpi-finger/contact_picture_border_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_0_blk.png b/res/drawable-hdpi-finger/dial_num_0_blk.png
new file mode 100644
index 0000000..960d968
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_0_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_0_wht.png b/res/drawable-hdpi-finger/dial_num_0_wht.png
new file mode 100644
index 0000000..c257817
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_0_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_1_no_vm_blk.png b/res/drawable-hdpi-finger/dial_num_1_no_vm_blk.png
new file mode 100644
index 0000000..d150354
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_1_no_vm_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_1_no_vm_wht.png b/res/drawable-hdpi-finger/dial_num_1_no_vm_wht.png
new file mode 100644
index 0000000..9a1152b
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_1_no_vm_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_2_blk.png b/res/drawable-hdpi-finger/dial_num_2_blk.png
new file mode 100644
index 0000000..7b0cee7
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_2_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_2_wht.png b/res/drawable-hdpi-finger/dial_num_2_wht.png
new file mode 100644
index 0000000..cad5485
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_2_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_3_blk.png b/res/drawable-hdpi-finger/dial_num_3_blk.png
new file mode 100644
index 0000000..d2efe88
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_3_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_3_wht.png b/res/drawable-hdpi-finger/dial_num_3_wht.png
new file mode 100644
index 0000000..ddb890c
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_3_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_4_blk.png b/res/drawable-hdpi-finger/dial_num_4_blk.png
new file mode 100644
index 0000000..fc3ed43
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_4_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_4_wht.png b/res/drawable-hdpi-finger/dial_num_4_wht.png
new file mode 100644
index 0000000..bb8064c
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_4_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_5_blk.png b/res/drawable-hdpi-finger/dial_num_5_blk.png
new file mode 100644
index 0000000..5c78c75
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_5_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_5_wht.png b/res/drawable-hdpi-finger/dial_num_5_wht.png
new file mode 100644
index 0000000..1368d36
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_5_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_6_blk.png b/res/drawable-hdpi-finger/dial_num_6_blk.png
new file mode 100644
index 0000000..583fb2a
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_6_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_6_wht.png b/res/drawable-hdpi-finger/dial_num_6_wht.png
new file mode 100644
index 0000000..7f1bf4a
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_6_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_7_blk.png b/res/drawable-hdpi-finger/dial_num_7_blk.png
new file mode 100644
index 0000000..793660b
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_7_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_7_wht.png b/res/drawable-hdpi-finger/dial_num_7_wht.png
new file mode 100644
index 0000000..d8038c7
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_7_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_8_blk.png b/res/drawable-hdpi-finger/dial_num_8_blk.png
new file mode 100644
index 0000000..0ee87fe
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_8_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_8_wht.png b/res/drawable-hdpi-finger/dial_num_8_wht.png
new file mode 100644
index 0000000..9d0d0eb
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_8_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_9_blk.png b/res/drawable-hdpi-finger/dial_num_9_blk.png
new file mode 100644
index 0000000..920235a
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_9_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_9_wht.png b/res/drawable-hdpi-finger/dial_num_9_wht.png
new file mode 100644
index 0000000..ac3727d
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_9_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_pound_blk.png b/res/drawable-hdpi-finger/dial_num_pound_blk.png
new file mode 100644
index 0000000..fcfc58c
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_pound_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_pound_wht.png b/res/drawable-hdpi-finger/dial_num_pound_wht.png
new file mode 100644
index 0000000..df67810
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_pound_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_star_blk.png b/res/drawable-hdpi-finger/dial_num_star_blk.png
new file mode 100644
index 0000000..ddda118
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_star_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/dial_num_star_wht.png b/res/drawable-hdpi-finger/dial_num_star_wht.png
new file mode 100644
index 0000000..ded1900
--- /dev/null
+++ b/res/drawable-hdpi-finger/dial_num_star_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/divider_vertical_dark.9.png b/res/drawable-hdpi-finger/divider_vertical_dark.9.png
new file mode 100644
index 0000000..702b878
--- /dev/null
+++ b/res/drawable-hdpi-finger/divider_vertical_dark.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_btn_round_minus.png b/res/drawable-hdpi-finger/ic_btn_round_minus.png
new file mode 100755
index 0000000..27af3fa
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_btn_round_minus.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_btn_round_more.png b/res/drawable-hdpi-finger/ic_btn_round_more.png
new file mode 100755
index 0000000..9883d55
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_btn_round_more.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_btn_round_plus.png b/res/drawable-hdpi-finger/ic_btn_round_plus.png
new file mode 100755
index 0000000..b24168c
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_btn_round_plus.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_call_log_header_incoming_call.png b/res/drawable-hdpi-finger/ic_call_log_header_incoming_call.png
new file mode 100755
index 0000000..95c0255
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_call_log_header_incoming_call.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_call_log_header_missed_call.png b/res/drawable-hdpi-finger/ic_call_log_header_missed_call.png
new file mode 100755
index 0000000..0a43e69
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_call_log_header_missed_call.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_call_log_header_outgoing_call.png b/res/drawable-hdpi-finger/ic_call_log_header_outgoing_call.png
new file mode 100755
index 0000000..d061ba3
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_call_log_header_outgoing_call.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_call_log_list_incoming_call.png b/res/drawable-hdpi-finger/ic_call_log_list_incoming_call.png
new file mode 100755
index 0000000..9c016fa
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_call_log_list_incoming_call.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_call_log_list_missed_call.png b/res/drawable-hdpi-finger/ic_call_log_list_missed_call.png
new file mode 100755
index 0000000..8dcb279
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_call_log_list_missed_call.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_call_log_list_outgoing_call.png b/res/drawable-hdpi-finger/ic_call_log_list_outgoing_call.png
new file mode 100755
index 0000000..256de19
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_call_log_list_outgoing_call.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_contact_list_picture.png b/res/drawable-hdpi-finger/ic_contact_list_picture.png
new file mode 100755
index 0000000..296ab9f
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_contact_list_picture.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_contact_picture.png b/res/drawable-hdpi-finger/ic_contact_picture.png
new file mode 100755
index 0000000..7c34f5c
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_contact_picture.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_contact_picture_2.png b/res/drawable-hdpi-finger/ic_contact_picture_2.png
new file mode 100755
index 0000000..5e65276
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_contact_picture_2.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_contact_picture_3.png b/res/drawable-hdpi-finger/ic_contact_picture_3.png
new file mode 100755
index 0000000..a8ec1e1
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_contact_picture_3.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_default_number.png b/res/drawable-hdpi-finger/ic_default_number.png
new file mode 100755
index 0000000..cdc05a8
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_default_number.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_dial_action_call.png b/res/drawable-hdpi-finger/ic_dial_action_call.png
new file mode 100644
index 0000000..1ba3a98
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_dial_action_call.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_dial_action_delete.png b/res/drawable-hdpi-finger/ic_dial_action_delete.png
new file mode 100644
index 0000000..2e206c8
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_dial_action_delete.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_dial_action_voice_mail.png b/res/drawable-hdpi-finger/ic_dial_action_voice_mail.png
new file mode 100644
index 0000000..8a3f366
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_dial_action_voice_mail.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_dial_number_blk.png b/res/drawable-hdpi-finger/ic_dial_number_blk.png
new file mode 100755
index 0000000..cad1d80
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_dial_number_blk.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_dial_number_wht.png b/res/drawable-hdpi-finger/ic_dial_number_wht.png
new file mode 100755
index 0000000..54f5ac0
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_dial_number_wht.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_dialer_fork_add_call.png b/res/drawable-hdpi-finger/ic_dialer_fork_add_call.png
new file mode 100755
index 0000000..e046996
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_dialer_fork_add_call.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_dialer_fork_current_call.png b/res/drawable-hdpi-finger/ic_dialer_fork_current_call.png
new file mode 100755
index 0000000..6e1a395
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_dialer_fork_current_call.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_dialer_fork_tt_keypad.png b/res/drawable-hdpi-finger/ic_dialer_fork_tt_keypad.png
new file mode 100755
index 0000000..6b50da1
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_dialer_fork_tt_keypad.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_join.png b/res/drawable-hdpi-finger/ic_join.png
new file mode 100644
index 0000000..8f140d4
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_join.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_list_split.png b/res/drawable-hdpi-finger/ic_list_split.png
new file mode 100644
index 0000000..92f486b
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_list_split.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_menu_account_list.png b/res/drawable-hdpi-finger/ic_menu_account_list.png
new file mode 100755
index 0000000..a69c642
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_menu_account_list.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_menu_add_picture.png b/res/drawable-hdpi-finger/ic_menu_add_picture.png
new file mode 100755
index 0000000..85faf1c
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_menu_add_picture.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_menu_export_contact.png b/res/drawable-hdpi-finger/ic_menu_export_contact.png
new file mode 100755
index 0000000..c9781f7
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_menu_export_contact.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_menu_import_contact.png b/res/drawable-hdpi-finger/ic_menu_import_contact.png
new file mode 100755
index 0000000..18de61f
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_menu_import_contact.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_menu_import_export.png b/res/drawable-hdpi-finger/ic_menu_import_export.png
new file mode 100644
index 0000000..4f1b608
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_menu_import_export.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_menu_merge.png b/res/drawable-hdpi-finger/ic_menu_merge.png
new file mode 100644
index 0000000..d3ed8cc
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_menu_merge.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_menu_show_barcode.png b/res/drawable-hdpi-finger/ic_menu_show_barcode.png
new file mode 100755
index 0000000..e36efdd
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_menu_show_barcode.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_menu_split.png b/res/drawable-hdpi-finger/ic_menu_split.png
new file mode 100644
index 0000000..33ef601
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_menu_split.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_tab_selected_contacts.png b/res/drawable-hdpi-finger/ic_tab_selected_contacts.png
new file mode 100644
index 0000000..7c92375
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_tab_selected_contacts.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_tab_selected_dialer.png b/res/drawable-hdpi-finger/ic_tab_selected_dialer.png
new file mode 100644
index 0000000..44b4db0
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_tab_selected_dialer.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_tab_selected_friends_list.png b/res/drawable-hdpi-finger/ic_tab_selected_friends_list.png
new file mode 100755
index 0000000..201b80f
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_tab_selected_friends_list.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_tab_selected_recent.png b/res/drawable-hdpi-finger/ic_tab_selected_recent.png
new file mode 100644
index 0000000..dfa268b
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_tab_selected_recent.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_tab_selected_starred.png b/res/drawable-hdpi-finger/ic_tab_selected_starred.png
new file mode 100644
index 0000000..d9182b5
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_tab_selected_starred.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_tab_unselected_contacts.png b/res/drawable-hdpi-finger/ic_tab_unselected_contacts.png
new file mode 100644
index 0000000..ee09bf1
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_tab_unselected_contacts.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_tab_unselected_dialer.png b/res/drawable-hdpi-finger/ic_tab_unselected_dialer.png
new file mode 100644
index 0000000..4151cd4
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_tab_unselected_dialer.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_tab_unselected_friends_list.png b/res/drawable-hdpi-finger/ic_tab_unselected_friends_list.png
new file mode 100755
index 0000000..6a31485
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_tab_unselected_friends_list.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_tab_unselected_recent.png b/res/drawable-hdpi-finger/ic_tab_unselected_recent.png
new file mode 100644
index 0000000..4ecfa21
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_tab_unselected_recent.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/ic_tab_unselected_starred.png b/res/drawable-hdpi-finger/ic_tab_unselected_starred.png
new file mode 100644
index 0000000..259d2d3
--- /dev/null
+++ b/res/drawable-hdpi-finger/ic_tab_unselected_starred.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/infobar_dark.9.png b/res/drawable-hdpi-finger/infobar_dark.9.png
new file mode 100644
index 0000000..5a08290
--- /dev/null
+++ b/res/drawable-hdpi-finger/infobar_dark.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_arrow_down.png b/res/drawable-hdpi-finger/quickcontact_arrow_down.png
new file mode 100644
index 0000000..7eba756
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_arrow_down.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_arrow_up.png b/res/drawable-hdpi-finger/quickcontact_arrow_up.png
new file mode 100644
index 0000000..6daf90a
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_arrow_up.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_bottom_frame.9.png b/res/drawable-hdpi-finger/quickcontact_bottom_frame.9.png
new file mode 100644
index 0000000..9fac225
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_bottom_frame.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_disambig_bottom_bg.9.png b/res/drawable-hdpi-finger/quickcontact_disambig_bottom_bg.9.png
new file mode 100644
index 0000000..4702f16
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_disambig_bottom_bg.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_disambig_checkbox_off.png b/res/drawable-hdpi-finger/quickcontact_disambig_checkbox_off.png
new file mode 100644
index 0000000..f87572c
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_disambig_checkbox_off.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_disambig_checkbox_on.png b/res/drawable-hdpi-finger/quickcontact_disambig_checkbox_on.png
new file mode 100644
index 0000000..3ea5360
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_disambig_checkbox_on.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_disambig_divider.9.png b/res/drawable-hdpi-finger/quickcontact_disambig_divider.9.png
new file mode 100644
index 0000000..8c35e8c
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_disambig_divider.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_drop_shadow.9.png b/res/drawable-hdpi-finger/quickcontact_drop_shadow.9.png
new file mode 100644
index 0000000..0dcf076
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_drop_shadow.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_frame_divider_med.png b/res/drawable-hdpi-finger/quickcontact_frame_divider_med.png
new file mode 100644
index 0000000..e0e9ca4
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_frame_divider_med.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_photo_frame.9.png b/res/drawable-hdpi-finger/quickcontact_photo_frame.9.png
new file mode 100644
index 0000000..990c75d
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_photo_frame.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_background.png b/res/drawable-hdpi-finger/quickcontact_slider_background.png
new file mode 100644
index 0000000..c9c09ee
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_background.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_btn_normal.9.png b/res/drawable-hdpi-finger/quickcontact_slider_btn_normal.9.png
new file mode 100644
index 0000000..9d3d7ad
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_btn_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_btn_on.9.png b/res/drawable-hdpi-finger/quickcontact_slider_btn_on.9.png
new file mode 100644
index 0000000..ac2b496
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_btn_on.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_btn_pressed.9.png b/res/drawable-hdpi-finger/quickcontact_slider_btn_pressed.9.png
new file mode 100644
index 0000000..d9da598
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_btn_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_btn_selected.9.png b/res/drawable-hdpi-finger/quickcontact_slider_btn_selected.9.png
new file mode 100644
index 0000000..72d053b
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_btn_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_grip_left.png b/res/drawable-hdpi-finger/quickcontact_slider_grip_left.png
new file mode 100644
index 0000000..97f12aa
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_grip_left.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_grip_right.png b/res/drawable-hdpi-finger/quickcontact_slider_grip_right.png
new file mode 100644
index 0000000..e410059
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_grip_right.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_presence_active.png b/res/drawable-hdpi-finger/quickcontact_slider_presence_active.png
new file mode 100644
index 0000000..f62e681
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_presence_active.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_presence_away.png b/res/drawable-hdpi-finger/quickcontact_slider_presence_away.png
new file mode 100644
index 0000000..0516b97
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_presence_away.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_presence_busy.png b/res/drawable-hdpi-finger/quickcontact_slider_presence_busy.png
new file mode 100644
index 0000000..26063f4
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_presence_busy.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_slider_presence_inactive.png b/res/drawable-hdpi-finger/quickcontact_slider_presence_inactive.png
new file mode 100644
index 0000000..fdcf75e
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_slider_presence_inactive.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/quickcontact_top_frame.9.png b/res/drawable-hdpi-finger/quickcontact_top_frame.9.png
new file mode 100644
index 0000000..4556bb2
--- /dev/null
+++ b/res/drawable-hdpi-finger/quickcontact_top_frame.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/sym_action_add.png b/res/drawable-hdpi-finger/sym_action_add.png
new file mode 100755
index 0000000..45a9ec5
--- /dev/null
+++ b/res/drawable-hdpi-finger/sym_action_add.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/sym_action_map.png b/res/drawable-hdpi-finger/sym_action_map.png
new file mode 100755
index 0000000..cf00c7b
--- /dev/null
+++ b/res/drawable-hdpi-finger/sym_action_map.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/sym_action_organization.png b/res/drawable-hdpi-finger/sym_action_organization.png
new file mode 100755
index 0000000..9db8b44
--- /dev/null
+++ b/res/drawable-hdpi-finger/sym_action_organization.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/sym_action_view_contact.png b/res/drawable-hdpi-finger/sym_action_view_contact.png
new file mode 100755
index 0000000..3a016ff
--- /dev/null
+++ b/res/drawable-hdpi-finger/sym_action_view_contact.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/sym_note.png b/res/drawable-hdpi-finger/sym_note.png
new file mode 100755
index 0000000..5257329
--- /dev/null
+++ b/res/drawable-hdpi-finger/sym_note.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/sym_ringtone.png b/res/drawable-hdpi-finger/sym_ringtone.png
new file mode 100755
index 0000000..ad103e8
--- /dev/null
+++ b/res/drawable-hdpi-finger/sym_ringtone.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/sym_send_to_voicemail.png b/res/drawable-hdpi-finger/sym_send_to_voicemail.png
new file mode 100755
index 0000000..ac43473
--- /dev/null
+++ b/res/drawable-hdpi-finger/sym_send_to_voicemail.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/tab_focused.9.png b/res/drawable-hdpi-finger/tab_focused.9.png
new file mode 100644
index 0000000..a65b8f5
--- /dev/null
+++ b/res/drawable-hdpi-finger/tab_focused.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/tab_focused_bottom.9.png b/res/drawable-hdpi-finger/tab_focused_bottom.9.png
new file mode 100644
index 0000000..2fe4a9b
--- /dev/null
+++ b/res/drawable-hdpi-finger/tab_focused_bottom.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/tab_left_arrow.png b/res/drawable-hdpi-finger/tab_left_arrow.png
new file mode 100644
index 0000000..c2274f1
--- /dev/null
+++ b/res/drawable-hdpi-finger/tab_left_arrow.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/tab_pressed.9.png b/res/drawable-hdpi-finger/tab_pressed.9.png
new file mode 100644
index 0000000..0f90065
--- /dev/null
+++ b/res/drawable-hdpi-finger/tab_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/tab_pressed_bottom.9.png b/res/drawable-hdpi-finger/tab_pressed_bottom.9.png
new file mode 100644
index 0000000..00361aa
--- /dev/null
+++ b/res/drawable-hdpi-finger/tab_pressed_bottom.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/tab_right_arrow.png b/res/drawable-hdpi-finger/tab_right_arrow.png
new file mode 100644
index 0000000..8a847e0
--- /dev/null
+++ b/res/drawable-hdpi-finger/tab_right_arrow.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/tab_selected.9.png b/res/drawable-hdpi-finger/tab_selected.9.png
new file mode 100644
index 0000000..08a39ff
--- /dev/null
+++ b/res/drawable-hdpi-finger/tab_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/tab_selected_bottom.9.png b/res/drawable-hdpi-finger/tab_selected_bottom.9.png
new file mode 100644
index 0000000..3cc26bc
--- /dev/null
+++ b/res/drawable-hdpi-finger/tab_selected_bottom.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/tab_unselected.9.png b/res/drawable-hdpi-finger/tab_unselected.9.png
new file mode 100644
index 0000000..6150b5b
--- /dev/null
+++ b/res/drawable-hdpi-finger/tab_unselected.9.png
Binary files differ
diff --git a/res/drawable-hdpi-finger/title_bar_shadow.9.png b/res/drawable-hdpi-finger/title_bar_shadow.9.png
new file mode 100755
index 0000000..a5e458a
--- /dev/null
+++ b/res/drawable-hdpi-finger/title_bar_shadow.9.png
Binary files differ
diff --git a/res/drawable-hdpi/bg_infobar_new.9.png b/res/drawable-hdpi/bg_infobar_new.9.png
new file mode 100644
index 0000000..104ced9
--- /dev/null
+++ b/res/drawable-hdpi/bg_infobar_new.9.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contacts_details.png b/res/drawable-hdpi/ic_contacts_details.png
new file mode 100755
index 0000000..35f8106
--- /dev/null
+++ b/res/drawable-hdpi/ic_contacts_details.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_contacts.png b/res/drawable-hdpi/ic_launcher_contacts.png
new file mode 100644
index 0000000..69a72c4
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts.png
new file mode 100644
index 0000000..84babe2
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_folder_live_contacts.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png
new file mode 100644
index 0000000..004e849
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png
new file mode 100644
index 0000000..73b4fa5
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_phone.png b/res/drawable-hdpi/ic_launcher_phone.png
new file mode 100644
index 0000000..0943ce5
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_shortcut_contact.png b/res/drawable-hdpi/ic_launcher_shortcut_contact.png
new file mode 100644
index 0000000..d86b264
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_shortcut_contact.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_shortcut_directdial.png b/res/drawable-hdpi/ic_launcher_shortcut_directdial.png
new file mode 100644
index 0000000..e7ff8f8
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_shortcut_directdial.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_shortcut_directmessage.png b/res/drawable-hdpi/ic_launcher_shortcut_directmessage.png
new file mode 100644
index 0000000..5170a75
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_shortcut_directmessage.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_mark.png b/res/drawable-hdpi/ic_menu_mark.png
new file mode 100755
index 0000000..724d787
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_mark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_sources.png b/res/drawable-hdpi/ic_menu_sources.png
new file mode 100644
index 0000000..45355e2
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_sources.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_action_sms.png b/res/drawable-hdpi/sym_action_sms.png
new file mode 100644
index 0000000..9f18105
--- /dev/null
+++ b/res/drawable-hdpi/sym_action_sms.png
Binary files differ
diff --git a/res/drawable-finger/badge_action_call.png b/res/drawable-mdpi-finger/badge_action_call.png
similarity index 100%
rename from res/drawable-finger/badge_action_call.png
rename to res/drawable-mdpi-finger/badge_action_call.png
Binary files differ
diff --git a/res/drawable-finger/badge_action_sms.png b/res/drawable-mdpi-finger/badge_action_sms.png
similarity index 100%
rename from res/drawable-finger/badge_action_sms.png
rename to res/drawable-mdpi-finger/badge_action_sms.png
Binary files differ
diff --git a/res/drawable-finger/btn_circle_disable.png b/res/drawable-mdpi-finger/btn_circle_disable.png
similarity index 100%
rename from res/drawable-finger/btn_circle_disable.png
rename to res/drawable-mdpi-finger/btn_circle_disable.png
Binary files differ
diff --git a/res/drawable-finger/btn_circle_disable_focused.png b/res/drawable-mdpi-finger/btn_circle_disable_focused.png
similarity index 100%
rename from res/drawable-finger/btn_circle_disable_focused.png
rename to res/drawable-mdpi-finger/btn_circle_disable_focused.png
Binary files differ
diff --git a/res/drawable-finger/btn_circle_normal.png b/res/drawable-mdpi-finger/btn_circle_normal.png
similarity index 100%
rename from res/drawable-finger/btn_circle_normal.png
rename to res/drawable-mdpi-finger/btn_circle_normal.png
Binary files differ
diff --git a/res/drawable-finger/btn_circle_pressed.png b/res/drawable-mdpi-finger/btn_circle_pressed.png
similarity index 100%
rename from res/drawable-finger/btn_circle_pressed.png
rename to res/drawable-mdpi-finger/btn_circle_pressed.png
Binary files differ
diff --git a/res/drawable-finger/btn_circle_selected.png b/res/drawable-mdpi-finger/btn_circle_selected.png
similarity index 100%
rename from res/drawable-finger/btn_circle_selected.png
rename to res/drawable-mdpi-finger/btn_circle_selected.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_left_disable.9.png b/res/drawable-mdpi-finger/btn_dial_action_left_disable.9.png
new file mode 100644
index 0000000..6ab27d8
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_left_disable.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_left_disable_focused.9.png b/res/drawable-mdpi-finger/btn_dial_action_left_disable_focused.9.png
new file mode 100644
index 0000000..5bba3c4
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_left_disable_focused.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_left_normal.9.png b/res/drawable-mdpi-finger/btn_dial_action_left_normal.9.png
new file mode 100644
index 0000000..6ab27d8
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_left_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_left_pressed.9.png b/res/drawable-mdpi-finger/btn_dial_action_left_pressed.9.png
new file mode 100644
index 0000000..542abe7
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_left_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_left_selected.9.png b/res/drawable-mdpi-finger/btn_dial_action_left_selected.9.png
new file mode 100644
index 0000000..34caba1
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_left_selected.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_middle_disable.9.png b/res/drawable-mdpi-finger/btn_dial_action_middle_disable.9.png
new file mode 100644
index 0000000..0740c95
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_middle_disable.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_middle_disable_focused.9.png b/res/drawable-mdpi-finger/btn_dial_action_middle_disable_focused.9.png
new file mode 100644
index 0000000..c57627f
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_middle_disable_focused.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_middle_normal.9.png b/res/drawable-mdpi-finger/btn_dial_action_middle_normal.9.png
new file mode 100644
index 0000000..0740c95
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_middle_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_middle_pressed.9.png b/res/drawable-mdpi-finger/btn_dial_action_middle_pressed.9.png
new file mode 100644
index 0000000..a5f9f98
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_middle_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_middle_selected.9.png b/res/drawable-mdpi-finger/btn_dial_action_middle_selected.9.png
new file mode 100644
index 0000000..dcd4b82
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_middle_selected.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_right_disable.9.png b/res/drawable-mdpi-finger/btn_dial_action_right_disable.9.png
new file mode 100644
index 0000000..85dfff0
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_right_disable.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_right_disable_focused.9.png b/res/drawable-mdpi-finger/btn_dial_action_right_disable_focused.9.png
new file mode 100644
index 0000000..1f76f0c
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_right_disable_focused.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_right_normal.9.png b/res/drawable-mdpi-finger/btn_dial_action_right_normal.9.png
new file mode 100644
index 0000000..85dfff0
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_right_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_right_pressed.9.png b/res/drawable-mdpi-finger/btn_dial_action_right_pressed.9.png
new file mode 100644
index 0000000..226633f
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_right_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_action_right_selected.9.png b/res/drawable-mdpi-finger/btn_dial_action_right_selected.9.png
new file mode 100644
index 0000000..9cca52c
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_action_right_selected.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_normal.9.png b/res/drawable-mdpi-finger/btn_dial_normal.9.png
new file mode 100644
index 0000000..748dd8a
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_normal_blue.9.png b/res/drawable-mdpi-finger/btn_dial_normal_blue.9.png
new file mode 100644
index 0000000..7c8c2ca
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_normal_blue.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_normal_green.9.png b/res/drawable-mdpi-finger/btn_dial_normal_green.9.png
new file mode 100644
index 0000000..b220650
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_normal_green.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_pressed.9.png b/res/drawable-mdpi-finger/btn_dial_pressed.9.png
new file mode 100644
index 0000000..83f9c62
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_selected.9.png b/res/drawable-mdpi-finger/btn_dial_selected.9.png
new file mode 100644
index 0000000..edc7bcb
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_selected.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_textfield_activated.9.png b/res/drawable-mdpi-finger/btn_dial_textfield_activated.9.png
new file mode 100644
index 0000000..de65d44
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_textfield_activated.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_textfield_normal.9.png b/res/drawable-mdpi-finger/btn_dial_textfield_normal.9.png
new file mode 100644
index 0000000..d3613e3
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_textfield_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_textfield_pressed.9.png b/res/drawable-mdpi-finger/btn_dial_textfield_pressed.9.png
new file mode 100644
index 0000000..fa7147e
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_textfield_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/btn_dial_textfield_selected.9.png b/res/drawable-mdpi-finger/btn_dial_textfield_selected.9.png
new file mode 100644
index 0000000..09db422
--- /dev/null
+++ b/res/drawable-mdpi-finger/btn_dial_textfield_selected.9.png
Binary files differ
diff --git a/res/drawable-finger/contact_picture_border_highlight.9.png b/res/drawable-mdpi-finger/contact_picture_border_highlight.9.png
similarity index 100%
rename from res/drawable-finger/contact_picture_border_highlight.9.png
rename to res/drawable-mdpi-finger/contact_picture_border_highlight.9.png
Binary files differ
diff --git a/res/drawable-finger/contact_picture_border_in_list.9.png b/res/drawable-mdpi-finger/contact_picture_border_in_list.9.png
similarity index 100%
rename from res/drawable-finger/contact_picture_border_in_list.9.png
rename to res/drawable-mdpi-finger/contact_picture_border_in_list.9.png
Binary files differ
diff --git a/res/drawable-finger/contact_picture_border_normal.9.png b/res/drawable-mdpi-finger/contact_picture_border_normal.9.png
similarity index 100%
rename from res/drawable-finger/contact_picture_border_normal.9.png
rename to res/drawable-mdpi-finger/contact_picture_border_normal.9.png
Binary files differ
diff --git a/res/drawable-finger/contact_picture_border_pressed.9.png b/res/drawable-mdpi-finger/contact_picture_border_pressed.9.png
similarity index 100%
rename from res/drawable-finger/contact_picture_border_pressed.9.png
rename to res/drawable-mdpi-finger/contact_picture_border_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_0_blk.png b/res/drawable-mdpi-finger/dial_num_0_blk.png
new file mode 100644
index 0000000..d04add7
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_0_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_0_wht.png b/res/drawable-mdpi-finger/dial_num_0_wht.png
new file mode 100644
index 0000000..c3b3f2c
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_0_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_1_no_vm_blk.png b/res/drawable-mdpi-finger/dial_num_1_no_vm_blk.png
new file mode 100644
index 0000000..75a8ed8
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_1_no_vm_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_1_no_vm_wht.png b/res/drawable-mdpi-finger/dial_num_1_no_vm_wht.png
new file mode 100644
index 0000000..a5bdb41
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_1_no_vm_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_2_blk.png b/res/drawable-mdpi-finger/dial_num_2_blk.png
new file mode 100644
index 0000000..1d8a35c
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_2_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_2_wht.png b/res/drawable-mdpi-finger/dial_num_2_wht.png
new file mode 100644
index 0000000..ac99cec
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_2_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_3_blk.png b/res/drawable-mdpi-finger/dial_num_3_blk.png
new file mode 100644
index 0000000..cf78e04
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_3_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_3_wht.png b/res/drawable-mdpi-finger/dial_num_3_wht.png
new file mode 100644
index 0000000..69170b9
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_3_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_4_blk.png b/res/drawable-mdpi-finger/dial_num_4_blk.png
new file mode 100644
index 0000000..c9c12c2
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_4_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_4_wht.png b/res/drawable-mdpi-finger/dial_num_4_wht.png
new file mode 100644
index 0000000..48a02a5
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_4_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_5_blk.png b/res/drawable-mdpi-finger/dial_num_5_blk.png
new file mode 100644
index 0000000..a89dd8f
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_5_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_5_wht.png b/res/drawable-mdpi-finger/dial_num_5_wht.png
new file mode 100644
index 0000000..e3c9940
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_5_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_6_blk.png b/res/drawable-mdpi-finger/dial_num_6_blk.png
new file mode 100644
index 0000000..c282afb
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_6_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_6_wht.png b/res/drawable-mdpi-finger/dial_num_6_wht.png
new file mode 100644
index 0000000..ab12781
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_6_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_7_blk.png b/res/drawable-mdpi-finger/dial_num_7_blk.png
new file mode 100644
index 0000000..df273a2
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_7_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_7_wht.png b/res/drawable-mdpi-finger/dial_num_7_wht.png
new file mode 100644
index 0000000..9e66205
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_7_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_8_blk.png b/res/drawable-mdpi-finger/dial_num_8_blk.png
new file mode 100644
index 0000000..9e5654f
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_8_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_8_wht.png b/res/drawable-mdpi-finger/dial_num_8_wht.png
new file mode 100644
index 0000000..2af30fa
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_8_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_9_blk.png b/res/drawable-mdpi-finger/dial_num_9_blk.png
new file mode 100644
index 0000000..6ae1943
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_9_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_9_wht.png b/res/drawable-mdpi-finger/dial_num_9_wht.png
new file mode 100644
index 0000000..1c99b61
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_9_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_pound_blk.png b/res/drawable-mdpi-finger/dial_num_pound_blk.png
new file mode 100644
index 0000000..add133e
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_pound_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_pound_wht.png b/res/drawable-mdpi-finger/dial_num_pound_wht.png
new file mode 100644
index 0000000..e17f2bf
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_pound_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_star_blk.png b/res/drawable-mdpi-finger/dial_num_star_blk.png
new file mode 100644
index 0000000..f649f14
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_star_blk.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/dial_num_star_wht.png b/res/drawable-mdpi-finger/dial_num_star_wht.png
new file mode 100644
index 0000000..86113ed
--- /dev/null
+++ b/res/drawable-mdpi-finger/dial_num_star_wht.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/divider_vertical_dark.9.png b/res/drawable-mdpi-finger/divider_vertical_dark.9.png
new file mode 100644
index 0000000..702b878
--- /dev/null
+++ b/res/drawable-mdpi-finger/divider_vertical_dark.9.png
Binary files differ
diff --git a/res/drawable-finger/ic_btn_round_minus.png b/res/drawable-mdpi-finger/ic_btn_round_minus.png
similarity index 100%
rename from res/drawable-finger/ic_btn_round_minus.png
rename to res/drawable-mdpi-finger/ic_btn_round_minus.png
Binary files differ
diff --git a/res/drawable-finger/ic_btn_round_more.png b/res/drawable-mdpi-finger/ic_btn_round_more.png
similarity index 100%
rename from res/drawable-finger/ic_btn_round_more.png
rename to res/drawable-mdpi-finger/ic_btn_round_more.png
Binary files differ
diff --git a/res/drawable-finger/ic_btn_round_plus.png b/res/drawable-mdpi-finger/ic_btn_round_plus.png
similarity index 100%
rename from res/drawable-finger/ic_btn_round_plus.png
rename to res/drawable-mdpi-finger/ic_btn_round_plus.png
Binary files differ
diff --git a/res/drawable-finger/ic_call_log_header_incoming_call.png b/res/drawable-mdpi-finger/ic_call_log_header_incoming_call.png
similarity index 100%
rename from res/drawable-finger/ic_call_log_header_incoming_call.png
rename to res/drawable-mdpi-finger/ic_call_log_header_incoming_call.png
Binary files differ
diff --git a/res/drawable-finger/ic_call_log_header_missed_call.png b/res/drawable-mdpi-finger/ic_call_log_header_missed_call.png
similarity index 100%
rename from res/drawable-finger/ic_call_log_header_missed_call.png
rename to res/drawable-mdpi-finger/ic_call_log_header_missed_call.png
Binary files differ
diff --git a/res/drawable-finger/ic_call_log_header_outgoing_call.png b/res/drawable-mdpi-finger/ic_call_log_header_outgoing_call.png
similarity index 100%
rename from res/drawable-finger/ic_call_log_header_outgoing_call.png
rename to res/drawable-mdpi-finger/ic_call_log_header_outgoing_call.png
Binary files differ
diff --git a/res/drawable-finger/ic_call_log_list_incoming_call.png b/res/drawable-mdpi-finger/ic_call_log_list_incoming_call.png
similarity index 100%
rename from res/drawable-finger/ic_call_log_list_incoming_call.png
rename to res/drawable-mdpi-finger/ic_call_log_list_incoming_call.png
Binary files differ
diff --git a/res/drawable-finger/ic_call_log_list_missed_call.png b/res/drawable-mdpi-finger/ic_call_log_list_missed_call.png
similarity index 100%
rename from res/drawable-finger/ic_call_log_list_missed_call.png
rename to res/drawable-mdpi-finger/ic_call_log_list_missed_call.png
Binary files differ
diff --git a/res/drawable-finger/ic_call_log_list_outgoing_call.png b/res/drawable-mdpi-finger/ic_call_log_list_outgoing_call.png
similarity index 100%
rename from res/drawable-finger/ic_call_log_list_outgoing_call.png
rename to res/drawable-mdpi-finger/ic_call_log_list_outgoing_call.png
Binary files differ
diff --git a/res/drawable-finger/ic_contact_list_picture.png b/res/drawable-mdpi-finger/ic_contact_list_picture.png
similarity index 100%
rename from res/drawable-finger/ic_contact_list_picture.png
rename to res/drawable-mdpi-finger/ic_contact_list_picture.png
Binary files differ
diff --git a/res/drawable-finger/ic_contact_picture.png b/res/drawable-mdpi-finger/ic_contact_picture.png
similarity index 100%
rename from res/drawable-finger/ic_contact_picture.png
rename to res/drawable-mdpi-finger/ic_contact_picture.png
Binary files differ
diff --git a/res/drawable-finger/ic_contact_picture_2.png b/res/drawable-mdpi-finger/ic_contact_picture_2.png
similarity index 100%
rename from res/drawable-finger/ic_contact_picture_2.png
rename to res/drawable-mdpi-finger/ic_contact_picture_2.png
Binary files differ
diff --git a/res/drawable-finger/ic_contact_picture_3.png b/res/drawable-mdpi-finger/ic_contact_picture_3.png
similarity index 100%
rename from res/drawable-finger/ic_contact_picture_3.png
rename to res/drawable-mdpi-finger/ic_contact_picture_3.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_default_number.png b/res/drawable-mdpi-finger/ic_default_number.png
new file mode 100644
index 0000000..30ead23
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_default_number.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_dial_action_call.png b/res/drawable-mdpi-finger/ic_dial_action_call.png
new file mode 100644
index 0000000..1942899
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_dial_action_call.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_dial_action_delete.png b/res/drawable-mdpi-finger/ic_dial_action_delete.png
new file mode 100644
index 0000000..440ae37
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_dial_action_delete.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_dial_action_voice_mail.png b/res/drawable-mdpi-finger/ic_dial_action_voice_mail.png
new file mode 100644
index 0000000..cb07d1a
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_dial_action_voice_mail.png
Binary files differ
diff --git a/res/drawable-finger/ic_dial_number_blk.png b/res/drawable-mdpi-finger/ic_dial_number_blk.png
similarity index 100%
rename from res/drawable-finger/ic_dial_number_blk.png
rename to res/drawable-mdpi-finger/ic_dial_number_blk.png
Binary files differ
diff --git a/res/drawable-finger/ic_dial_number_wht.png b/res/drawable-mdpi-finger/ic_dial_number_wht.png
similarity index 100%
rename from res/drawable-finger/ic_dial_number_wht.png
rename to res/drawable-mdpi-finger/ic_dial_number_wht.png
Binary files differ
diff --git a/res/drawable-finger/ic_dialer_fork_add_call.png b/res/drawable-mdpi-finger/ic_dialer_fork_add_call.png
similarity index 100%
rename from res/drawable-finger/ic_dialer_fork_add_call.png
rename to res/drawable-mdpi-finger/ic_dialer_fork_add_call.png
Binary files differ
diff --git a/res/drawable-finger/ic_dialer_fork_current_call.png b/res/drawable-mdpi-finger/ic_dialer_fork_current_call.png
similarity index 100%
rename from res/drawable-finger/ic_dialer_fork_current_call.png
rename to res/drawable-mdpi-finger/ic_dialer_fork_current_call.png
Binary files differ
diff --git a/res/drawable-finger/ic_dialer_fork_tt_keypad.png b/res/drawable-mdpi-finger/ic_dialer_fork_tt_keypad.png
similarity index 100%
rename from res/drawable-finger/ic_dialer_fork_tt_keypad.png
rename to res/drawable-mdpi-finger/ic_dialer_fork_tt_keypad.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_join.png b/res/drawable-mdpi-finger/ic_join.png
new file mode 100644
index 0000000..177a582
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_join.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_list_split.png b/res/drawable-mdpi-finger/ic_list_split.png
new file mode 100644
index 0000000..cbaab12
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_list_split.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_menu_account_list.png b/res/drawable-mdpi-finger/ic_menu_account_list.png
new file mode 100644
index 0000000..f0945b2
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_menu_account_list.png
Binary files differ
diff --git a/res/drawable-finger/ic_menu_add_picture.png b/res/drawable-mdpi-finger/ic_menu_add_picture.png
similarity index 100%
rename from res/drawable-finger/ic_menu_add_picture.png
rename to res/drawable-mdpi-finger/ic_menu_add_picture.png
Binary files differ
diff --git a/res/drawable-finger/ic_menu_export_contact.png b/res/drawable-mdpi-finger/ic_menu_export_contact.png
similarity index 100%
rename from res/drawable-finger/ic_menu_export_contact.png
rename to res/drawable-mdpi-finger/ic_menu_export_contact.png
Binary files differ
diff --git a/res/drawable-finger/ic_menu_import_contact.png b/res/drawable-mdpi-finger/ic_menu_import_contact.png
similarity index 100%
rename from res/drawable-finger/ic_menu_import_contact.png
rename to res/drawable-mdpi-finger/ic_menu_import_contact.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_menu_import_export.png b/res/drawable-mdpi-finger/ic_menu_import_export.png
new file mode 100644
index 0000000..1cefb7c
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_menu_import_export.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_menu_merge.png b/res/drawable-mdpi-finger/ic_menu_merge.png
new file mode 100644
index 0000000..b448c27
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_menu_merge.png
Binary files differ
diff --git a/res/drawable-finger/ic_menu_show_barcode.png b/res/drawable-mdpi-finger/ic_menu_show_barcode.png
similarity index 100%
rename from res/drawable-finger/ic_menu_show_barcode.png
rename to res/drawable-mdpi-finger/ic_menu_show_barcode.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_menu_split.png b/res/drawable-mdpi-finger/ic_menu_split.png
new file mode 100644
index 0000000..9d69e4c
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_menu_split.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_tab_selected_contacts.png b/res/drawable-mdpi-finger/ic_tab_selected_contacts.png
new file mode 100644
index 0000000..b3e23b7
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_tab_selected_contacts.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_tab_selected_dialer.png b/res/drawable-mdpi-finger/ic_tab_selected_dialer.png
new file mode 100644
index 0000000..71739a6
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_tab_selected_dialer.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_tab_selected_friends_list.png b/res/drawable-mdpi-finger/ic_tab_selected_friends_list.png
new file mode 100644
index 0000000..de2c4cc
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_tab_selected_friends_list.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_tab_selected_recent.png b/res/drawable-mdpi-finger/ic_tab_selected_recent.png
new file mode 100644
index 0000000..a6cbc2a
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_tab_selected_recent.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_tab_selected_starred.png b/res/drawable-mdpi-finger/ic_tab_selected_starred.png
new file mode 100644
index 0000000..089dfe9
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_tab_selected_starred.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_tab_unselected_contacts.png b/res/drawable-mdpi-finger/ic_tab_unselected_contacts.png
new file mode 100644
index 0000000..b3f5ae0
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_tab_unselected_contacts.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_tab_unselected_dialer.png b/res/drawable-mdpi-finger/ic_tab_unselected_dialer.png
new file mode 100644
index 0000000..f008813
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_tab_unselected_dialer.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_tab_unselected_friends_list.png b/res/drawable-mdpi-finger/ic_tab_unselected_friends_list.png
new file mode 100644
index 0000000..80736e9
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_tab_unselected_friends_list.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_tab_unselected_recent.png b/res/drawable-mdpi-finger/ic_tab_unselected_recent.png
new file mode 100644
index 0000000..8f81688
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_tab_unselected_recent.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/ic_tab_unselected_starred.png b/res/drawable-mdpi-finger/ic_tab_unselected_starred.png
new file mode 100644
index 0000000..32fe67d
--- /dev/null
+++ b/res/drawable-mdpi-finger/ic_tab_unselected_starred.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/infobar_dark.9.png b/res/drawable-mdpi-finger/infobar_dark.9.png
new file mode 100644
index 0000000..ae3caf7
--- /dev/null
+++ b/res/drawable-mdpi-finger/infobar_dark.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_arrow_down.png b/res/drawable-mdpi-finger/quickcontact_arrow_down.png
new file mode 100644
index 0000000..3ba6c8c
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_arrow_down.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_arrow_up.png b/res/drawable-mdpi-finger/quickcontact_arrow_up.png
new file mode 100644
index 0000000..1a6fa2e
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_arrow_up.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_bottom_frame.9.png b/res/drawable-mdpi-finger/quickcontact_bottom_frame.9.png
new file mode 100644
index 0000000..6f84306
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_bottom_frame.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_disambig_bottom_bg.9.png b/res/drawable-mdpi-finger/quickcontact_disambig_bottom_bg.9.png
new file mode 100644
index 0000000..bbc2075
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_disambig_bottom_bg.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_disambig_checkbox_off.png b/res/drawable-mdpi-finger/quickcontact_disambig_checkbox_off.png
new file mode 100644
index 0000000..7e51863
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_disambig_checkbox_off.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_disambig_checkbox_on.png b/res/drawable-mdpi-finger/quickcontact_disambig_checkbox_on.png
new file mode 100644
index 0000000..93c06aa
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_disambig_checkbox_on.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_disambig_divider.9.png b/res/drawable-mdpi-finger/quickcontact_disambig_divider.9.png
new file mode 100644
index 0000000..8c35e8c
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_disambig_divider.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_drop_shadow.9.png b/res/drawable-mdpi-finger/quickcontact_drop_shadow.9.png
new file mode 100644
index 0000000..2d20076
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_drop_shadow.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_frame_divider_med.png b/res/drawable-mdpi-finger/quickcontact_frame_divider_med.png
new file mode 100644
index 0000000..3b24f95
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_frame_divider_med.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_photo_frame.9.png b/res/drawable-mdpi-finger/quickcontact_photo_frame.9.png
new file mode 100644
index 0000000..a509c30
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_photo_frame.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_background.png b/res/drawable-mdpi-finger/quickcontact_slider_background.png
new file mode 100644
index 0000000..b6a9f91
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_background.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_btn_normal.9.png b/res/drawable-mdpi-finger/quickcontact_slider_btn_normal.9.png
new file mode 100644
index 0000000..cf4f1e4
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_btn_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_btn_on.9.png b/res/drawable-mdpi-finger/quickcontact_slider_btn_on.9.png
new file mode 100644
index 0000000..330f49b
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_btn_on.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_btn_pressed.9.png b/res/drawable-mdpi-finger/quickcontact_slider_btn_pressed.9.png
new file mode 100644
index 0000000..d4916f5
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_btn_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_btn_selected.9.png b/res/drawable-mdpi-finger/quickcontact_slider_btn_selected.9.png
new file mode 100644
index 0000000..b910028
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_btn_selected.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_grip_left.png b/res/drawable-mdpi-finger/quickcontact_slider_grip_left.png
new file mode 100644
index 0000000..337b2fc
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_grip_left.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_grip_right.png b/res/drawable-mdpi-finger/quickcontact_slider_grip_right.png
new file mode 100644
index 0000000..1e222c3
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_grip_right.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_presence_active.png b/res/drawable-mdpi-finger/quickcontact_slider_presence_active.png
new file mode 100644
index 0000000..2d57813
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_presence_active.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_presence_away.png b/res/drawable-mdpi-finger/quickcontact_slider_presence_away.png
new file mode 100644
index 0000000..22d014b
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_presence_away.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_presence_busy.png b/res/drawable-mdpi-finger/quickcontact_slider_presence_busy.png
new file mode 100644
index 0000000..5734e00
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_presence_busy.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_slider_presence_inactive.png b/res/drawable-mdpi-finger/quickcontact_slider_presence_inactive.png
new file mode 100644
index 0000000..81731a8
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_slider_presence_inactive.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/quickcontact_top_frame.9.png b/res/drawable-mdpi-finger/quickcontact_top_frame.9.png
new file mode 100644
index 0000000..6d43305
--- /dev/null
+++ b/res/drawable-mdpi-finger/quickcontact_top_frame.9.png
Binary files differ
diff --git a/res/drawable-finger/sym_action_add.png b/res/drawable-mdpi-finger/sym_action_add.png
similarity index 100%
rename from res/drawable-finger/sym_action_add.png
rename to res/drawable-mdpi-finger/sym_action_add.png
Binary files differ
diff --git a/res/drawable-finger/sym_action_map.png b/res/drawable-mdpi-finger/sym_action_map.png
similarity index 100%
rename from res/drawable-finger/sym_action_map.png
rename to res/drawable-mdpi-finger/sym_action_map.png
Binary files differ
diff --git a/res/drawable-finger/sym_action_organization.png b/res/drawable-mdpi-finger/sym_action_organization.png
similarity index 100%
rename from res/drawable-finger/sym_action_organization.png
rename to res/drawable-mdpi-finger/sym_action_organization.png
Binary files differ
diff --git a/res/drawable-finger/sym_action_view_contact.png b/res/drawable-mdpi-finger/sym_action_view_contact.png
similarity index 100%
rename from res/drawable-finger/sym_action_view_contact.png
rename to res/drawable-mdpi-finger/sym_action_view_contact.png
Binary files differ
diff --git a/res/drawable-finger/sym_note.png b/res/drawable-mdpi-finger/sym_note.png
similarity index 100%
rename from res/drawable-finger/sym_note.png
rename to res/drawable-mdpi-finger/sym_note.png
Binary files differ
diff --git a/res/drawable-finger/sym_ringtone.png b/res/drawable-mdpi-finger/sym_ringtone.png
similarity index 100%
rename from res/drawable-finger/sym_ringtone.png
rename to res/drawable-mdpi-finger/sym_ringtone.png
Binary files differ
diff --git a/res/drawable-finger/sym_send_to_voicemail.png b/res/drawable-mdpi-finger/sym_send_to_voicemail.png
similarity index 100%
rename from res/drawable-finger/sym_send_to_voicemail.png
rename to res/drawable-mdpi-finger/sym_send_to_voicemail.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/tab_focused.9.png b/res/drawable-mdpi-finger/tab_focused.9.png
new file mode 100644
index 0000000..6190694
--- /dev/null
+++ b/res/drawable-mdpi-finger/tab_focused.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/tab_focused_bottom.9.png b/res/drawable-mdpi-finger/tab_focused_bottom.9.png
new file mode 100644
index 0000000..0e3bdb0
--- /dev/null
+++ b/res/drawable-mdpi-finger/tab_focused_bottom.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/tab_left_arrow.png b/res/drawable-mdpi-finger/tab_left_arrow.png
new file mode 100644
index 0000000..e35d58d
--- /dev/null
+++ b/res/drawable-mdpi-finger/tab_left_arrow.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/tab_pressed.9.png b/res/drawable-mdpi-finger/tab_pressed.9.png
new file mode 100644
index 0000000..dbada51
--- /dev/null
+++ b/res/drawable-mdpi-finger/tab_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/tab_pressed_bottom.9.png b/res/drawable-mdpi-finger/tab_pressed_bottom.9.png
new file mode 100644
index 0000000..4bf95d5
--- /dev/null
+++ b/res/drawable-mdpi-finger/tab_pressed_bottom.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/tab_right_arrow.png b/res/drawable-mdpi-finger/tab_right_arrow.png
new file mode 100644
index 0000000..8acbba0
--- /dev/null
+++ b/res/drawable-mdpi-finger/tab_right_arrow.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/tab_selected.9.png b/res/drawable-mdpi-finger/tab_selected.9.png
new file mode 100644
index 0000000..b3c9fb1
--- /dev/null
+++ b/res/drawable-mdpi-finger/tab_selected.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/tab_selected_bottom.9.png b/res/drawable-mdpi-finger/tab_selected_bottom.9.png
new file mode 100644
index 0000000..f69f08e
--- /dev/null
+++ b/res/drawable-mdpi-finger/tab_selected_bottom.9.png
Binary files differ
diff --git a/res/drawable-mdpi-finger/tab_unselected.9.png b/res/drawable-mdpi-finger/tab_unselected.9.png
new file mode 100644
index 0000000..a79fa2a
--- /dev/null
+++ b/res/drawable-mdpi-finger/tab_unselected.9.png
Binary files differ
diff --git a/res/drawable-finger/title_bar_shadow.9.png b/res/drawable-mdpi-finger/title_bar_shadow.9.png
similarity index 100%
rename from res/drawable-finger/title_bar_shadow.9.png
rename to res/drawable-mdpi-finger/title_bar_shadow.9.png
Binary files differ
diff --git a/res/drawable-mdpi/bg_infobar_new.9.png b/res/drawable-mdpi/bg_infobar_new.9.png
new file mode 100644
index 0000000..f3a83d4
--- /dev/null
+++ b/res/drawable-mdpi/bg_infobar_new.9.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contacts_details.png b/res/drawable-mdpi/ic_contacts_details.png
new file mode 100644
index 0000000..7e71b85
--- /dev/null
+++ b/res/drawable-mdpi/ic_contacts_details.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_contacts.png b/res/drawable-mdpi/ic_launcher_contacts.png
new file mode 100644
index 0000000..08468fd
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts.png
new file mode 100644
index 0000000..d49cc7b
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_folder_live_contacts.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png
new file mode 100644
index 0000000..0127f84
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png
new file mode 100644
index 0000000..8d56b31
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_phone.png b/res/drawable-mdpi/ic_launcher_phone.png
new file mode 100644
index 0000000..724f94a
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut_contact.png b/res/drawable-mdpi/ic_launcher_shortcut_contact.png
new file mode 100644
index 0000000..20d359d
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_shortcut_contact.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut_directdial.png b/res/drawable-mdpi/ic_launcher_shortcut_directdial.png
new file mode 100644
index 0000000..7081c08
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_shortcut_directdial.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut_directmessage.png b/res/drawable-mdpi/ic_launcher_shortcut_directmessage.png
new file mode 100644
index 0000000..374c7c4
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_shortcut_directmessage.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_mark.png b/res/drawable-mdpi/ic_menu_mark.png
new file mode 100644
index 0000000..5e95da7
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_mark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_sources.png b/res/drawable-mdpi/ic_menu_sources.png
new file mode 100644
index 0000000..78cdaca
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_sources.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_action_sms.png b/res/drawable-mdpi/sym_action_sms.png
new file mode 100644
index 0000000..f098f4a
--- /dev/null
+++ b/res/drawable-mdpi/sym_action_sms.png
Binary files differ
diff --git a/res/drawable-finger/ic_delete_phone_number.xml b/res/drawable/btn_dial_textfield.xml
similarity index 71%
rename from res/drawable-finger/ic_delete_phone_number.xml
rename to res/drawable/btn_dial_textfield.xml
index adfc0ce..de914cf 100644
--- a/res/drawable-finger/ic_delete_phone_number.xml
+++ b/res/drawable/btn_dial_textfield.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -15,11 +15,11 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/ic_delete_phone_number_blk" />
+ <item android:state_pressed="true"
+ android:drawable="@drawable/btn_dial_textfield_pressed" />
<item android:state_focused="true"
- android:drawable="@drawable/ic_delete_phone_number_blk" />
+ android:drawable="@drawable/btn_dial_textfield_selected" />
<item
- android:drawable="@drawable/ic_delete_phone_number_wht" />
+ android:drawable="@drawable/btn_dial_textfield_normal" />
</selector>
diff --git a/res/drawable-finger/ic_delete_phone_number.xml b/res/drawable/btn_dial_textfield_active.xml
similarity index 71%
copy from res/drawable-finger/ic_delete_phone_number.xml
copy to res/drawable/btn_dial_textfield_active.xml
index adfc0ce..f3af301 100644
--- a/res/drawable-finger/ic_delete_phone_number.xml
+++ b/res/drawable/btn_dial_textfield_active.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -15,11 +15,11 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/ic_delete_phone_number_blk" />
+ <item android:state_pressed="true"
+ android:drawable="@drawable/btn_dial_textfield_pressed" />
<item android:state_focused="true"
- android:drawable="@drawable/ic_delete_phone_number_blk" />
+ android:drawable="@drawable/btn_dial_textfield_selected" />
<item
- android:drawable="@drawable/ic_delete_phone_number_wht" />
+ android:drawable="@drawable/btn_dial_textfield_activated" />
</selector>
diff --git a/res/drawable-finger/ic_delete_phone_number.xml b/res/drawable/call_background.xml
similarity index 60%
copy from res/drawable-finger/ic_delete_phone_number.xml
copy to res/drawable/call_background.xml
index adfc0ce..fbc9b3c 100644
--- a/res/drawable-finger/ic_delete_phone_number.xml
+++ b/res/drawable/call_background.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!-- 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.
@@ -15,11 +15,12 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/ic_delete_phone_number_blk" />
- <item android:state_focused="true"
- android:drawable="@drawable/ic_delete_phone_number_blk" />
- <item
- android:drawable="@drawable/ic_delete_phone_number_wht" />
-</selector>
+ <item android:state_window_focused="false"
+ android:drawable="@android:color/transparent" />
+ <item android:state_focused="false" android:state_pressed="true"
+ android:drawable="@*android:drawable/list_selector_background_transition" />
+ <item android:state_focused="false" android:state_pressed="false"
+ android:drawable="@android:drawable/screen_background_dark"/>
+
+</selector>
diff --git a/res/drawable/ic_launcher_contacts.png b/res/drawable/ic_launcher_contacts.png
deleted file mode 100644
index 826656f..0000000
--- a/res/drawable/ic_launcher_contacts.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/ic_menu_2sec_pause.png b/res/drawable/ic_menu_2sec_pause.png
new file mode 100644
index 0000000..dcaa5ff
--- /dev/null
+++ b/res/drawable/ic_menu_2sec_pause.png
Binary files differ
diff --git a/res/drawable/ic_menu_wait.png b/res/drawable/ic_menu_wait.png
new file mode 100644
index 0000000..c20457a
--- /dev/null
+++ b/res/drawable/ic_menu_wait.png
Binary files differ
diff --git a/res/drawable/quickcontact.9.png b/res/drawable/quickcontact.9.png
new file mode 100644
index 0000000..fa0b917
--- /dev/null
+++ b/res/drawable/quickcontact.9.png
Binary files differ
diff --git a/res/drawable/section_dark.9.png b/res/drawable/section_dark.9.png
new file mode 100644
index 0000000..5d1e1ae
--- /dev/null
+++ b/res/drawable/section_dark.9.png
Binary files differ
diff --git a/res/drawable/unknown_source.png b/res/drawable/unknown_source.png
new file mode 100644
index 0000000..356748f
--- /dev/null
+++ b/res/drawable/unknown_source.png
Binary files differ
diff --git a/res/layout-finger/all_tab_indicator.xml b/res/layout-finger/all_tab_indicator.xml
new file mode 100644
index 0000000..25294c4
--- /dev/null
+++ b/res/layout-finger/all_tab_indicator.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="40dip"
+ android:layout_weight="1"
+ android:layout_marginLeft="-3dip"
+ android:layout_marginRight="-3dip"
+ android:minWidth="72dip"
+ android:background="@+drawable/tab_indicator_bg">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:text="@string/all_tab_label"
+ android:textColor="@color/tab_indicator_text"
+ android:textSize="20dip"
+ />
+
+</RelativeLayout>
diff --git a/res/layout-finger/contact_card_layout.xml b/res/layout-finger/contact_card_layout.xml
new file mode 100644
index 0000000..6e70561
--- /dev/null
+++ b/res/layout-finger/contact_card_layout.xml
@@ -0,0 +1,53 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/card_root_view"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <com.android.internal.widget.ContactHeaderWidget
+ android:id="@+id/contact_header_widget"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ <ListView android:id="@+id/contact_data"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@drawable/title_bar_shadow"
+ />
+
+ <ScrollView android:id="@android:id/empty"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:fillViewport="true"
+ >
+ <TextView android:id="@+id/emptyText"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/no_contact_details"
+ android:textSize="20sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:paddingLeft="10dip"
+ android:paddingRight="10dip"
+ android:paddingTop="10dip"
+ android:lineSpacingMultiplier="0.92"
+ />
+ </ScrollView>
+
+</LinearLayout>
+
diff --git a/res/layout-finger/contact_options.xml b/res/layout-finger/contact_options.xml
new file mode 100644
index 0000000..e484324
--- /dev/null
+++ b/res/layout-finger/contact_options.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+>
+
+ <include layout="@layout/edit_contact_entry_ringtone" android:id="@+id/ringtone" />
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider"
+ />
+ <include layout="@layout/edit_contact_entry_voicemail" android:id="@+id/voicemail"/>
+
+</LinearLayout>
diff --git a/res/layout-finger/contacts_list_content.xml b/res/layout-finger/contacts_list_content.xml
index 1f37dcf..f736efd 100644
--- a/res/layout-finger/contacts_list_content.xml
+++ b/res/layout-finger/contacts_list_content.xml
@@ -19,7 +19,7 @@
android:layout_height="fill_parent"
android:orientation="vertical">
- <ListView android:id="@android:id/list"
+ <com.android.contacts.FocusRequestingListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fastScrollEnabled="true"
diff --git a/res/layout-finger/contacts_list_content_join.xml b/res/layout-finger/contacts_list_content_join.xml
new file mode 100644
index 0000000..b59c1b7
--- /dev/null
+++ b/res/layout-finger/contacts_list_content_join.xml
@@ -0,0 +1,70 @@
+<?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.
+-->
+
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:background="@*android:drawable/title_bar_medium"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:gravity="center_vertical"
+ >
+
+ <ImageView
+ android:layout_width="48dip"
+ android:layout_height="48dip"
+ android:src="@drawable/ic_join"
+ android:gravity="center"
+ android:scaleType="fitCenter"
+ />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="10dip">
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/titleJoinContactDataWith"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:shadowColor="#BB000000"
+ android:shadowRadius="2.75"
+ />
+ <TextView
+ android:id="@+id/join_contact_blurb"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-2dip"
+ android:maxLines="2"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+ </LinearLayout>
+ </LinearLayout>
+
+ <ListView android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:fastScrollEnabled="true"
+ />
+</LinearLayout>
+
diff --git a/res/layout-finger/contacts_list_item.xml b/res/layout-finger/contacts_list_item.xml
index 713ac33..61cc839 100644
--- a/res/layout-finger/contacts_list_item.xml
+++ b/res/layout-finger/contacts_list_item.xml
@@ -17,65 +17,115 @@
*/
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:paddingLeft="14dip"
- android:paddingRight="5dip"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
>
-
- <ImageView android:id="@+id/presence"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="5dip"
- android:layout_centerVertical="true"
-
- android:gravity="center"
- android:scaleType="centerInside"
+ <include
+ android:id="@+id/header"
+ layout="@layout/list_section"
/>
- <TextView android:id="@+id/label"
- android:layout_width="wrap_content"
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="14dip"
+ >
+
+ <LinearLayout android:id="@+id/right_side"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:orientation="horizontal"
+ android:layout_marginLeft="11dip"
+ android:layout_alignParentRight="true">
+
+ <ImageView android:id="@+id/presence"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:layout_marginRight="5dip"
+ android:padding="7dip"
+ android:layout_gravity="center_vertical"
+ android:scaleType="centerInside"
+ />
+
+ <LinearLayout android:id="@+id/call_view"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:orientation="horizontal">
+
+ <View android:id="@+id/divider"
+ android:layout_width="1px"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ android:background="@drawable/divider_vertical_dark"
+ />
+
+ <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_button"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:paddingLeft="14dip"
+ android:paddingRight="14dip"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:src="@android:drawable/sym_action_call"
+ android:background="@drawable/call_background"
+ />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <TextView android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="8dip"
+ android:layout_marginTop="-8dip"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ />
+
+ <TextView android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:layout_toRightOf="@id/label"
+ android:layout_alignBaseline="@id/label"
+ android:layout_toLeftOf="@id/right_side"
+ android:layout_alignWithParentIfMissing="true"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+
+ <TextView android:id="@+id/name"
+ android:layout_width="0dip"
+ android:layout_height="0dip"
+ android:layout_above="@id/label"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_toLeftOf="@id/right_side"
+ android:layout_marginBottom="1dip"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:gravity="center_vertical|left"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
+ </RelativeLayout>
+
+ <View android:id="@+id/list_divider"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="8dip"
- android:layout_marginTop="-8dip"
-
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
+ android:background="@*android:drawable/divider_horizontal_dark_opaque"
/>
-
- <TextView android:id="@+id/number"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:layout_toRightOf="@id/label"
- android:layout_alignBaseline="@id/label"
- android:layout_toLeftOf="@id/presence"
- android:layout_alignWithParentIfMissing="true"
-
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall"
- />
-
- <TextView android:id="@+id/name"
- android:layout_width="0dip"
- android:layout_height="0dip"
- android:layout_above="@id/label"
- android:layout_alignWithParentIfMissing="true"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@id/presence"
- android:layout_marginBottom="1dip"
-
- android:singleLine="true"
- android:ellipsize="marquee"
- android:gravity="center_vertical|left"
- android:textAppearance="?android:attr/textAppearanceLarge"
- />
-
-</RelativeLayout>
+</LinearLayout>
diff --git a/res/layout-finger/contacts_list_item_photo.xml b/res/layout-finger/contacts_list_item_photo.xml
index c208b93..c9b4c1c 100644
--- a/res/layout-finger/contacts_list_item_photo.xml
+++ b/res/layout-finger/contacts_list_item_photo.xml
@@ -17,77 +17,129 @@
*/
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:paddingLeft="5dip"
- android:paddingRight="5dip"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
>
-
- <ImageView android:id="@+id/presence"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="5dip"
- android:layout_centerVertical="true"
-
- android:gravity="center"
- android:scaleType="centerInside"
+ <include
+ android:id="@+id/header"
+ layout="@layout/list_section"
/>
- <ImageView android:id="@+id/photo"
- android:layout_width="54dip"
- android:layout_height="54dip"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginRight="8dip"
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="4dip"
+ >
- android:gravity="center"
- android:scaleType="fitCenter"
- android:background="@drawable/contact_picture_border_in_list"
- />
+ <LinearLayout android:id="@+id/right_side"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:orientation="horizontal"
+ android:layout_marginLeft="11dip"
+ android:layout_alignParentRight="true">
- <TextView android:id="@+id/label"
- android:layout_width="wrap_content"
+ <ImageView android:id="@+id/presence"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:layout_marginRight="5dip"
+ android:padding="7dip"
+ android:layout_gravity="center_vertical"
+ android:scaleType="centerInside"
+ />
+
+ <LinearLayout android:id="@+id/call_view"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:orientation="horizontal">
+
+ <View android:id="@+id/divider"
+ android:layout_width="1px"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ android:background="@drawable/divider_vertical_dark"
+ />
+
+ <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_button"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:paddingLeft="14dip"
+ android:paddingRight="14dip"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:src="@android:drawable/sym_action_call"
+ android:background="@drawable/call_background"
+ />
+
+ </LinearLayout>
+ </LinearLayout>
+
+ <android.widget.QuickContactBadge android:id="@+id/photo"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dip"
+ style="@*android:style/Widget.QuickContactBadge.WindowMedium" />
+ />
+
+ <ImageView android:id="@+id/noQuickContactPhoto"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dip"
+ style="@*android:style/Widget.QuickContactBadge.WindowMedium"
+ android:background="@null" />
+ />
+
+ <TextView android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/photo"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="8dip"
+ android:layout_marginTop="-10dip"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ />
+
+ <TextView android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:layout_toRightOf="@id/label"
+ android:layout_toLeftOf="@id/right_side"
+ android:layout_alignBaseline="@id/label"
+ android:layout_alignWithParentIfMissing="true"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+
+ <TextView android:id="@+id/name"
+ android:layout_width="0dip"
+ android:layout_height="0dip"
+ android:layout_toRightOf="@id/photo"
+ android:layout_toLeftOf="@id/right_side"
+ android:layout_alignParentTop="true"
+ android:layout_above="@id/label"
+ android:layout_alignWithParentIfMissing="true"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:gravity="center_vertical|left"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
+
+ </RelativeLayout>
+
+ <View android:id="@+id/list_divider"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_toRightOf="@id/photo"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="8dip"
- android:layout_marginTop="-10dip"
-
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
+ android:background="@*android:drawable/divider_horizontal_dark_opaque"
/>
-
- <TextView android:id="@+id/number"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:layout_toRightOf="@id/label"
- android:layout_toLeftOf="@id/presence"
- android:layout_alignBaseline="@id/label"
- android:layout_alignWithParentIfMissing="true"
-
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall"
- />
-
- <TextView android:id="@+id/name"
- android:layout_width="0dip"
- android:layout_height="0dip"
- android:layout_toRightOf="@id/photo"
- android:layout_toLeftOf="@id/presence"
- android:layout_alignParentTop="true"
- android:layout_above="@id/label"
- android:layout_alignWithParentIfMissing="true"
-
- android:singleLine="true"
- android:ellipsize="marquee"
- android:gravity="center_vertical|left"
- android:textAppearance="?android:attr/textAppearanceLarge"
- />
-
-</RelativeLayout>
+</LinearLayout>
diff --git a/res/layout-finger/contacts_list_show_all_item.xml b/res/layout-finger/contacts_list_show_all_item.xml
new file mode 100644
index 0000000..5937b9f
--- /dev/null
+++ b/res/layout-finger/contacts_list_show_all_item.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 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.
+ */
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+>
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical|left"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:text="@string/showAllContactsJoinItem"
+ android:paddingLeft="14dip"
+ />
+
+ <View android:id="@+id/list_divider"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="@*android:drawable/divider_horizontal_dark_opaque"
+ />
+</LinearLayout>
diff --git a/res/layout-finger/create_new_contact.xml b/res/layout-finger/create_new_contact.xml
new file mode 100644
index 0000000..776c482
--- /dev/null
+++ b/res/layout-finger/create_new_contact.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:orientation="horizontal"
+ android:paddingRight="6dip"
+ android:paddingLeft="6dip"
+ android:paddingTop="5dip"
+ android:paddingBottom="5dip"
+ android:gravity="center_vertical"
+ >
+ <ImageView android:id="@+id/addicon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:layout_marginRight="11dip"
+ android:focusable="false"
+ android:src="@*android:drawable/sym_action_add"
+ android:scaleType="fitCenter"
+ />
+ <TextView android:id="@+id/title"
+ android:text="@string/pickerNewContactHeader"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="2dip"
+ />
+</LinearLayout>
diff --git a/res/layout-finger/dialer_activity.xml b/res/layout-finger/dialer_activity.xml
index 242821b..29189c7 100644
--- a/res/layout-finger/dialer_activity.xml
+++ b/res/layout-finger/dialer_activity.xml
@@ -26,10 +26,7 @@
<TabWidget android:id="@android:id/tabs"
android:layout_width="fill_parent"
- android:layout_height="68dip"
- android:paddingLeft="1dip"
- android:paddingRight="1dip"
- android:paddingTop="4dip"
+ android:layout_height="wrap_content"
/>
<FrameLayout android:id="@android:id/tabcontent"
diff --git a/res/layout-finger/dialpad.xml b/res/layout-finger/dialpad.xml
index 8f367e5..1eb653d 100644
--- a/res/layout-finger/dialpad.xml
+++ b/res/layout-finger/dialpad.xml
@@ -4,9 +4,9 @@
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.
@@ -14,25 +14,32 @@
limitations under the License.
-->
+<!-- Dialpad in the Contact app.
+ -->
+
<com.android.contacts.ButtonGridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialpad"
- android:paddingLeft="16px"
- android:paddingRight="16px"
- android:layout_width="fill_parent"
+ android:paddingLeft="7dp"
+ android:paddingRight="7dp"
+ android:paddingTop="6dp"
+ android:paddingBottom="6dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="1"
>
<ImageButton android:id="@+id/one"
- android:layout_width="96px"
- android:layout_height="76px"
- android:src="@drawable/dial_num_1"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
+ android:src="@drawable/dial_num_1_no_vm"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
android:contentDescription="@string/description_image_button_one"
/>
-
+
<ImageButton android:id="@+id/two"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_2"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
@@ -40,8 +47,8 @@
/>
<ImageButton android:id="@+id/three"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_3"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
@@ -49,17 +56,17 @@
/>
<ImageButton android:id="@+id/four"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_4"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
android:contentDescription="@string/description_image_button_four"
/>
-
+
<ImageButton android:id="@+id/five"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_5"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
@@ -67,8 +74,8 @@
/>
<ImageButton android:id="@+id/six"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_6"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
@@ -76,17 +83,17 @@
/>
<ImageButton android:id="@+id/seven"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_7"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
android:contentDescription="@string/description_image_button_seven"
/>
-
+
<ImageButton android:id="@+id/eight"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_8"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
@@ -94,8 +101,8 @@
/>
<ImageButton android:id="@+id/nine"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_9"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
@@ -103,17 +110,17 @@
/>
<ImageButton android:id="@+id/star"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_star"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
android:contentDescription="@string/description_image_button_star"
/>
-
+
<ImageButton android:id="@+id/zero"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_0"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
@@ -121,8 +128,8 @@
/>
<ImageButton android:id="@+id/pound"
- android:layout_width="96px"
- android:layout_height="76px"
+ android:layout_width="88dp"
+ android:layout_height="50dp"
android:src="@drawable/dial_num_pound"
android:background="@drawable/btn_dial"
android:soundEffectsEnabled="false"
diff --git a/res/layout-finger/dialpad_chooser_list_item.xml b/res/layout-finger/dialpad_chooser_list_item.xml
index c5abeac..c836f5d 100644
--- a/res/layout-finger/dialpad_chooser_list_item.xml
+++ b/res/layout-finger/dialpad_chooser_list_item.xml
@@ -21,8 +21,8 @@
android:layout_height="fill_parent">
<ImageView android:id="@+id/icon"
- android:layout_width="64px"
- android:layout_height="64px"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
android:scaleType="center" />
<TextView android:id="@+id/text"
diff --git a/res/layout-finger/display_child.xml b/res/layout-finger/display_child.xml
new file mode 100644
index 0000000..ed4856a
--- /dev/null
+++ b/res/layout-finger/display_child.xml
@@ -0,0 +1,71 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
+ android:paddingRight="?android:attr/scrollbarSize"
+>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1"
+ android:duplicateParentState="true"
+ >
+
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:duplicateParentState="true"
+ />
+
+ <TextView
+ android:id="@android:id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/text1"
+ android:layout_alignLeft="@android:id/text1"
+ android:maxLines="2"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:duplicateParentState="true"
+ />
+
+ </RelativeLayout>
+
+ <CheckBox
+ android:id="@android:id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="4dip"
+ android:focusable="false"
+ android:clickable="false"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:duplicateParentState="true"
+ />
+
+</LinearLayout>
diff --git a/res/layout-finger/display_group.xml b/res/layout-finger/display_group.xml
new file mode 100644
index 0000000..7d36450
--- /dev/null
+++ b/res/layout-finger/display_group.xml
@@ -0,0 +1,55 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
+ android:paddingRight="?android:attr/scrollbarSize">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1"
+ android:duplicateParentState="true">
+
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:duplicateParentState="true" />
+
+ <TextView
+ android:id="@android:id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/text1"
+ android:layout_alignLeft="@android:id/text1"
+ android:maxLines="2"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:duplicateParentState="true" />
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/res/layout-finger/display_header.xml b/res/layout-finger/display_header.xml
new file mode 100644
index 0000000..65f82aa
--- /dev/null
+++ b/res/layout-finger/display_header.xml
@@ -0,0 +1,66 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingRight="?android:attr/scrollbarSize"
+>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="20dip"
+ android:layout_marginRight="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1"
+ >
+
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
+
+ <TextView
+ android:id="@android:id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/text1"
+ android:layout_alignLeft="@android:id/text1"
+ android:maxLines="2"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+
+ </RelativeLayout>
+
+ <CheckBox
+ android:id="@android:id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="4dip"
+ android:focusable="false"
+ android:clickable="false"
+ android:gravity="center_vertical"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/res/layout-finger/edit_contact.xml b/res/layout-finger/edit_contact.xml
index a3a1849..e91f7e9 100644
--- a/res/layout-finger/edit_contact.xml
+++ b/res/layout-finger/edit_contact.xml
@@ -13,105 +13,110 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:fillViewport="true">
- <LinearLayout
+ <ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:orientation="vertical"
- >
-
- <LinearLayout android:id="@+id/banner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:padding="0dip"
- android:gravity="center_vertical"
- android:baselineAligned="false"
- >
-
- <FrameLayout
- android:layout_width="76dip"
- android:layout_height="76dip"
- android:layout_marginTop="4dip"
- android:layout_marginLeft="6dip"
- android:layout_marginBottom="6dip"
- android:layout_marginRight="2dip"
- >
- <ImageView android:id="@+id/photoImage"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:clickable="true"
- android:focusable="true"
- android:src="@drawable/ic_menu_add_picture"
- android:scaleType="center"
- android:background="@drawable/btn_contact_picture"
- />
- </FrameLayout>
-
- <EditText android:id="@+id/name"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:layout_marginRight="?android:attr/scrollbarSize"
- android:gravity="center_vertical"
- android:inputType="textPersonName|textCapWords"
- android:hint="@string/ghostData_name"
- android:nextFocusDown="@id/data"
- />
-
- <ImageView android:id="@+id/star"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- />
- </LinearLayout>
-
- <!-- "Phonetic name" entry widget, visible only in certain locales -->
- <include layout="@layout/edit_phonetic_name"/>
+ android:layout_weight="1"
+ android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
+ android:layout_height="fill_parent"
android:orientation="vertical"
- >
+ >
- <!-- The edit items -->
- <LinearLayout android:id="@+id/list"
+ <LinearLayout android:id="@+id/banner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="0dip"
+ android:gravity="center_vertical"
+ android:baselineAligned="false"
+ >
+
+ <FrameLayout
+ android:layout_width="76dip"
+ android:layout_height="76dip"
+ android:layout_marginTop="4dip"
+ android:layout_marginLeft="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_marginRight="2dip"
+ >
+ <ImageView android:id="@+id/photoImage"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:clickable="true"
+ android:focusable="true"
+ android:src="@drawable/ic_menu_add_picture"
+ android:scaleType="center"
+ android:background="@drawable/btn_contact_picture"
+ />
+ </FrameLayout>
+
+ <EditText android:id="@+id/name"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="?android:attr/scrollbarSize"
+ android:gravity="center_vertical"
+ android:inputType="textPersonName|textCapWords"
+ android:hint="@string/ghostData_name"
+ android:nextFocusDown="@id/data"
+ />
+
+ <ImageView android:id="@+id/star"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+ </LinearLayout>
+
+ <!-- "Phonetic name" entry widget, visible only in certain locales -->
+ <include layout="@layout/edit_phonetic_name"/>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
android:orientation="vertical"
- />
+ >
+ <!-- The edit items -->
+ <LinearLayout android:id="@+id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ />
+
+ </LinearLayout>
</LinearLayout>
+ </ScrollView>
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- style="@android:style/ButtonBar"
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ style="@android:style/ButtonBar"
>
- <Button android:id="@+id/saveButton"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/menu_done"
- />
+ <Button android:id="@+id/saveButton"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/menu_done"
+ />
- <Button android:id="@+id/discardButton"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/menu_doNotSave"
- />
+ <Button android:id="@+id/discardButton"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/menu_doNotSave"
+ />
- </LinearLayout>
-
</LinearLayout>
-</ScrollView>
+</LinearLayout>
diff --git a/res/layout-finger/edit_contact_entry_group.xml b/res/layout-finger/edit_contact_entry_group.xml
new file mode 100644
index 0000000..b233ca8
--- /dev/null
+++ b/res/layout-finger/edit_contact_entry_group.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/entry_group"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingRight="?android:attr/scrollbarSize"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:background="@android:drawable/list_selector_background"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:focusable="true"
+ android:clickable="true"
+ >
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="14dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1"
+ android:duplicateParentState="true"
+ >
+
+ <TextView android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:duplicateParentState="true"
+ />
+
+ <TextView android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/label"
+ android:layout_alignLeft="@+id/label"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:duplicateParentState="true"
+ />
+
+ </RelativeLayout>
+
+ <ImageView
+ style="@style/MoreButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+</LinearLayout>
diff --git a/res/layout-finger/view_contact_name.xml b/res/layout-finger/empty.xml
similarity index 62%
copy from res/layout-finger/view_contact_name.xml
copy to res/layout-finger/empty.xml
index 126c69b..8e70c24 100644
--- a/res/layout-finger/view_contact_name.xml
+++ b/res/layout-finger/empty.xml
@@ -14,15 +14,7 @@
limitations under the License.
-->
-<!-- In the default locale, the "Name" field is a single TextView -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/name"
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/empty"
android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:shadowColor="#BB000000"
- android:shadowRadius="2.75"
- android:maxLines="2"
- android:ellipsize="end"
- />
+ android:layout_height="0dip" />
diff --git a/res/layout-finger/list_item_text_icons.xml b/res/layout-finger/list_item_text_icons.xml
index 7f6ad1c..8d4b7a8 100644
--- a/res/layout-finger/list_item_text_icons.xml
+++ b/res/layout-finger/list_item_text_icons.xml
@@ -23,26 +23,17 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:paddingLeft="9dip"
- android:paddingRight="5dip"
android:gravity="center_vertical"
>
- <ImageView android:id="@+id/icon1"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_marginRight="5dip"
- android:gravity="center"
- android:scaleType="centerInside"
- />
-
<LinearLayout
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="5dip"
+ android:orientation="vertical"
android:paddingTop="5dip"
android:paddingBottom="7dip"
- android:orientation="vertical"
android:gravity="center_vertical"
>
@@ -52,20 +43,73 @@
android:textAppearance="?android:attr/textAppearanceLarge"
/>
- <TextView android:id="@android:id/text2"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+
+ <TextView android:id="@android:id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+
+ <ImageView android:id="@+id/primary_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingLeft="3dip"
+ android:src="@drawable/ic_default_number"
+ />
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/footer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
- />
+ android:visibility="gone" />
</LinearLayout>
- <ImageView android:id="@+id/icon2"
- android:layout_width="32dip"
- android:layout_height="32dip"
+ <ImageView android:id="@+id/presence_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:gravity="center"
android:scaleType="centerInside"
/>
+ <ImageView android:id="@+id/action_icon"
+ android:layout_width="30dip"
+ android:layout_height="30dip"
+ android:layout_marginLeft="14dip"
+ android:layout_marginRight="14dip"
+ android:gravity="center"
+ android:scaleType="centerInside"
+ />
+
+ <View android:id="@+id/divider"
+ android:layout_width="1px"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ android:background="@drawable/divider_vertical_dark"
+ />
+
+ <ImageView android:id="@+id/secondary_action_button"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:layout_centerVertical="true"
+ android:paddingLeft="14dip"
+ android:paddingRight="14dip"
+ android:gravity="center"
+ android:scaleType="center"
+ android:background="@android:drawable/list_selector_background"
+ />
+
</LinearLayout>
diff --git a/res/layout-finger/list_section.xml b/res/layout-finger/list_section.xml
new file mode 100644
index 0000000..06a9ffe
--- /dev/null
+++ b/res/layout-finger/list_section.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Layout used for list section separators. -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="25dip"
+ android:background="@*android:drawable/dark_header"
+ >
+ <TextView
+ android:id="@+id/header_text"
+ android:layout_width="56dip"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"
+ android:textStyle="bold"
+ android:textColor="@*android:color/dim_foreground_dark"
+ android:textSize="14sp"
+ android:gravity="center"
+ />
+</RelativeLayout>
diff --git a/res/layout-finger/list_separator.xml b/res/layout-finger/list_separator.xml
index 0c21541..2ab4859 100644
--- a/res/layout-finger/list_separator.xml
+++ b/res/layout-finger/list_separator.xml
@@ -17,4 +17,6 @@
<!-- Layout used for list separators. -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
style="?android:attr/listSeparatorTextViewStyle"
+ android:textColor="@*android:color/dim_foreground_dark"
+ android:gravity="center_horizontal"
/>
diff --git a/res/layout-finger/quickcontact.xml b/res/layout-finger/quickcontact.xml
new file mode 100644
index 0000000..13b5c20
--- /dev/null
+++ b/res/layout-finger/quickcontact.xml
@@ -0,0 +1,148 @@
+<?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.
+-->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/quickcontact_shadow_horiz"
+ android:paddingRight="@dimen/quickcontact_shadow_horiz"
+ android:background="@drawable/quickcontact_drop_shadow">
+
+ <FrameLayout
+ android:id="@+id/header"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip">
+
+ <ViewStub
+ android:id="@+id/header_small"
+ android:inflatedId="@+id/header_small"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout="@layout/quickcontact_header_small" />
+
+ <ViewStub
+ android:id="@+id/header_medium"
+ android:inflatedId="@+id/header_medium"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout="@layout/quickcontact_header_med" />
+
+ <ViewStub
+ android:id="@+id/header_large"
+ android:inflatedId="@+id/header_large"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout="@layout/quickcontact_header_large" />
+
+ </FrameLayout>
+
+ <HorizontalScrollView
+ android:id="@+id/scroll"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/header"
+ android:fadingEdgeLength="0dip"
+ android:background="@drawable/quickcontact_slider_background"
+ android:scrollbars="none">
+
+ <LinearLayout
+ android:id="@+id/quickcontact"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="4dip"
+ android:paddingBottom="4dip"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/quickcontact_slider_grip_left" />
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/quickcontact_slider_grip_right" />
+
+ </LinearLayout>
+
+ </HorizontalScrollView>
+
+ <FrameLayout
+ android:id="@+id/footer"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/scroll"
+ android:background="@drawable/quickcontact_bottom_frame" />
+
+ <LinearLayout
+ android:id="@+id/footer_disambig"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/scroll"
+ android:background="@drawable/quickcontact_disambig_bottom_bg"
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:background="@color/quickcontact_disambig"
+ android:divider="@drawable/quickcontact_disambig_divider"
+ android:cacheColorHint="@null" />
+
+ <CheckBox
+ android:id="@android:id/checkbox"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="19dip"
+ android:layout_marginRight="19dip"
+ android:minHeight="60dip"
+ android:textColor="#f000"
+ android:textStyle="bold"
+ android:text="@string/quickcontact_remember_choice"
+ android:textAppearance="?android:attr/textAppearanceSmallInverse"
+ android:button="@drawable/quickcontact_disambig_checkbox" />
+
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/arrow_up"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/quickcontact_arrow_up" />
+
+ <ImageView
+ android:id="@+id/arrow_down"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-1dip"
+ android:layout_below="@id/footer"
+ android:src="@drawable/quickcontact_arrow_down" />
+
+ <ImageView
+ android:id="@+id/arrow_down_stub"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-1dip"
+ android:layout_below="@id/footer_disambig"
+ android:visibility="invisible"
+ android:src="@drawable/quickcontact_arrow_down" />
+
+</RelativeLayout>
diff --git a/res/layout-finger/quickcontact_header_large.xml b/res/layout-finger/quickcontact_header_large.xml
new file mode 100644
index 0000000..2271ff1
--- /dev/null
+++ b/res/layout-finger/quickcontact_header_large.xml
@@ -0,0 +1,82 @@
+<?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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/header_large"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="87dip"
+ android:background="@drawable/quickcontact_top_frame"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/photo"
+ android:layout_width="54dip"
+ android:layout_height="57dip"
+ android:layout_marginLeft="15dip"
+ android:background="@drawable/quickcontact_photo_frame" />
+
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="15dip"
+ android:paddingRight="8dip"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/name"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textColor="@*android:color/primary_text_light"
+ android:textStyle="bold"
+ android:textSize="18dip" />
+
+ <TextView
+ android:id="@+id/status"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textColor="@*android:color/secondary_text_light"
+ android:textSize="15dip"
+ android:layout_marginTop="-3dip" />
+
+ <TextView
+ android:id="@+id/timestamp"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textColor="@*android:color/secondary_text_light"
+ android:textSize="12dip"
+ android:layout_marginTop="-2dip" />
+
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/presence"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="15dip"
+ android:src="@drawable/quickcontact_slider_presence_active"
+ android:scaleType="centerInside" />
+
+</LinearLayout>
diff --git a/res/layout-finger/quickcontact_header_med.xml b/res/layout-finger/quickcontact_header_med.xml
new file mode 100644
index 0000000..c9ef2be
--- /dev/null
+++ b/res/layout-finger/quickcontact_header_med.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/header_medium"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="51dip"
+ android:background="@drawable/quickcontact_top_frame"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="15dip"
+ android:layout_marginRight="15dip"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/status"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textColor="@*android:color/primary_text_light"
+ android:textSize="15sp" />
+
+ <TextView
+ android:id="@+id/timestamp"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textColor="@*android:color/secondary_text_light"
+ android:textSize="12sp"
+ android:layout_marginTop="-2dip" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout-finger/view_contact_name.xml b/res/layout-finger/quickcontact_header_small.xml
similarity index 62%
copy from res/layout-finger/view_contact_name.xml
copy to res/layout-finger/quickcontact_header_small.xml
index 126c69b..3711dcc 100644
--- a/res/layout-finger/view_contact_name.xml
+++ b/res/layout-finger/quickcontact_header_small.xml
@@ -4,9 +4,9 @@
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.
@@ -14,15 +14,10 @@
limitations under the License.
-->
-<!-- In the default locale, the "Name" field is a single TextView -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/name"
- android:layout_width="0dip"
- android:layout_weight="1"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/header_small"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:shadowColor="#BB000000"
- android:shadowRadius="2.75"
- android:maxLines="2"
- android:ellipsize="end"
- />
+ android:background="@drawable/quickcontact_top_frame"
+ android:orientation="horizontal" />
diff --git a/res/layout-finger/quickcontact_item.xml b/res/layout-finger/quickcontact_item.xml
new file mode 100644
index 0000000..8580ac5
--- /dev/null
+++ b/res/layout-finger/quickcontact_item.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<com.android.contacts.ui.widget.CheckableImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="59dip"
+ android:layout_height="51dip"
+ android:paddingLeft="12dip"
+ android:paddingRight="12dip"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"
+ android:scaleType="centerInside"
+ android:focusable="true"
+ android:clickable="true"
+ android:background="@drawable/quickcontact_slider_btn" />
diff --git a/res/layout-ja-finger/view_contact_name.xml b/res/layout-finger/quickcontact_resolve_item.xml
old mode 100644
new mode 100755
similarity index 63%
rename from res/layout-ja-finger/view_contact_name.xml
rename to res/layout-finger/quickcontact_resolve_item.xml
index bd72bba..9156a59
--- a/res/layout-ja-finger/view_contact_name.xml
+++ b/res/layout-finger/quickcontact_resolve_item.xml
@@ -14,28 +14,27 @@
limitations under the License.
-->
-<!-- In Japanese-language locales, the "Name" field contains two separate
- TextViews: the name itself, and also the phonetic ("furigana") field. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="wrap_content">
+ android:paddingLeft="30dip"
+ android:paddingRight="30dip"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical">
- <TextView android:id="@+id/name"
+ <TextView
+ android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:shadowColor="#BB000000"
- android:shadowRadius="2.75"
- />
+ android:textStyle="bold"
+ android:textAppearance="?android:attr/textAppearanceMediumInverse" />
- <TextView android:id="@+id/phonetic_name"
+ <TextView
+ android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:shadowColor="#BB000000"
- android:shadowRadius="2.75"
- />
+ android:layout_marginTop="-4dip"
+ android:textAppearance="?android:attr/textAppearanceSmallInverse" />
</LinearLayout>
diff --git a/res/layout-finger/recent_calls_list_item.xml b/res/layout-finger/recent_calls_list_item.xml
index bab9ea1..5439ff3 100644
--- a/res/layout-finger/recent_calls_list_item.xml
+++ b/res/layout-finger/recent_calls_list_item.xml
@@ -4,9 +4,9 @@
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.
@@ -17,44 +17,44 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
- android:paddingLeft="0dip"
- android:paddingRight="12dip"
+ android:paddingLeft="7dip"
>
- <ImageView android:id="@+id/call_icon"
+ <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
-
android:paddingLeft="14dip"
- android:paddingRight="11dip"
-
+ android:paddingRight="14dip"
+ android:layout_alignParentRight="true"
+
android:gravity="center_vertical"
android:src="@android:drawable/sym_action_call"
- android:background="@android:drawable/list_selector_background"
+ android:background="@drawable/call_background"
/>
<View android:id="@+id/divider"
- android:layout_width="1dip"
+ android:layout_width="1px"
android:layout_height="fill_parent"
- android:layout_toRightOf="@id/call_icon"
- android:layout_marginRight="11dip"
-
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ android:layout_toLeftOf="@id/call_icon"
+ android:layout_marginLeft="11dip"
android:background="@drawable/divider_vertical_dark"
/>
<ImageView android:id="@+id/call_type_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
+ android:layout_toLeftOf="@id/divider"
/>
-
+
<TextView android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
+ android:layout_toLeftOf="@id/divider"
android:layout_alignParentBottom="true"
- android:layout_marginBottom="9dip"
+ android:layout_marginBottom="8dip"
android:textAppearance="?android:attr/textAppearanceSmall"
android:singleLine="true"
@@ -63,7 +63,7 @@
<TextView android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_toRightOf="@id/divider"
+ android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="8dip"
android:layout_marginTop="-10dip"
@@ -88,19 +88,19 @@
android:textAppearance="?android:attr/textAppearanceSmall"
/>
-
<TextView android:id="@+id/line1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_toRightOf="@id/divider"
- android:layout_toLeftOf="@id/call_type_icon"
+ android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
+ android:layout_toLeftOf="@+id/call_type_icon"
android:layout_above="@id/label"
android:layout_alignWithParentIfMissing="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:singleLine="true"
+ android:ellipsize="marquee"
android:gravity="center_vertical"
/>
-
+
</RelativeLayout>
diff --git a/res/layout-finger/set_primary_checkbox.xml b/res/layout-finger/set_primary_checkbox.xml
new file mode 100644
index 0000000..bba8cf9
--- /dev/null
+++ b/res/layout-finger/set_primary_checkbox.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="14dip"
+ android:paddingRight="15dip"
+ android:orientation="vertical">
+
+ <CheckBox
+ android:id="@+id/setPrimary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:clickable="true"
+ android:text="@string/make_primary"/>
+</LinearLayout>
diff --git a/res/layout-finger/split_aggregate_list_item.xml b/res/layout-finger/split_aggregate_list_item.xml
new file mode 100644
index 0000000..5bd4270
--- /dev/null
+++ b/res/layout-finger/split_aggregate_list_item.xml
@@ -0,0 +1,70 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="12dip"
+ android:paddingRight="12dip"
+>
+ <ImageView
+ android:id="@+id/sourceIcon"
+ android:layout_width="32dip"
+ android:layout_height="32dip"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_centerVertical="true"
+ android:layout_marginTop="15dip"
+ android:layout_marginLeft="5dip"
+ android:layout_marginRight="8dip"
+
+ android:gravity="center"
+ android:scaleType="centerInside"
+ />
+
+ <TextView android:id="@+id/additionalData"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/sourceIcon"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_marginBottom="8dip"
+ android:layout_marginTop="-8dip"
+
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ />
+
+ <TextView android:id="@+id/name"
+ android:layout_width="0dip"
+ android:layout_height="0dip"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_above="@id/additionalData"
+ android:layout_toLeftOf="@id/sourceIcon"
+ android:layout_marginBottom="1dip"
+
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:gravity="center_vertical|left"
+ />
+
+</RelativeLayout>
diff --git a/res/layout-finger/tab_account_name.xml b/res/layout-finger/tab_account_name.xml
new file mode 100644
index 0000000..dc99af1
--- /dev/null
+++ b/res/layout-finger/tab_account_name.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<!-- looks like Widget.TextView.ListSeparator -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/account_name"
+ android:background="@drawable/bg_infobar_new"
+ android:layout_width="fill_parent"
+ android:layout_height="@dimen/account_name_height"
+ android:layout_below="@+id/tab_scroll_view"
+ android:textStyle="normal"
+ android:textColor="@*android:color/dim_foreground_dark"
+ android:textSize="12sp"
+ android:gravity="left|center_vertical"
+ android:paddingLeft="7dip"
+/>
diff --git a/res/layout-finger/tab_indicator.xml b/res/layout-finger/tab_indicator.xml
new file mode 100644
index 0000000..d43265c
--- /dev/null
+++ b/res/layout-finger/tab_indicator.xml
@@ -0,0 +1,41 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/tab_height"
+ android:layout_weight="1"
+ android:layout_marginLeft="-3dip"
+ android:layout_marginRight="-3dip"
+ android:minWidth="72dip"
+ android:background="@+drawable/tab_indicator_bg">
+
+ <ImageView android:id="@+id/tab_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ />
+
+ <TextView android:id="@+id/tab_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:textColor="@+color/tab_indicator_text"
+ android:textSize="20dip"
+ />
+
+</RelativeLayout>
diff --git a/res/layout-finger/view_contact_name.xml b/res/layout-finger/tab_layout.xml
similarity index 61%
copy from res/layout-finger/view_contact_name.xml
copy to res/layout-finger/tab_layout.xml
index 126c69b..9a793c3 100644
--- a/res/layout-finger/view_contact_name.xml
+++ b/res/layout-finger/tab_layout.xml
@@ -14,15 +14,17 @@
limitations under the License.
-->
-<!-- In the default locale, the "Name" field is a single TextView -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/name"
- android:layout_width="0dip"
- android:layout_weight="1"
+<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tab_scroll_view"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:shadowColor="#BB000000"
- android:shadowRadius="2.75"
- android:maxLines="2"
- android:ellipsize="end"
+ android:layout_alignParentLeft="true"
+ android:scrollbars="none"
+ android:fadingEdgeLength="0dip">
+
+ <com.android.contacts.TabStripView
+ android:id="@android:id/tabs"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
/>
+</HorizontalScrollView>
\ No newline at end of file
diff --git a/res/layout-finger/view_contact_name.xml b/res/layout-finger/tab_left_arrow.xml
similarity index 62%
copy from res/layout-finger/view_contact_name.xml
copy to res/layout-finger/tab_left_arrow.xml
index 126c69b..0ed2e57 100644
--- a/res/layout-finger/view_contact_name.xml
+++ b/res/layout-finger/tab_left_arrow.xml
@@ -14,15 +14,14 @@
limitations under the License.
-->
-<!-- In the default locale, the "Name" field is a single TextView -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/name"
- android:layout_width="0dip"
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/arrow"
+ android:layout_width="32dip"
+ android:layout_height="37dip"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
android:layout_weight="1"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:shadowColor="#BB000000"
- android:shadowRadius="2.75"
- android:maxLines="2"
- android:ellipsize="end"
+ android:background="@drawable/tab_indicator_bg"
+ android:scaleType="centerInside"
+ android:src="@drawable/tab_left_arrow"
/>
diff --git a/res/layout-finger/view_contact_name.xml b/res/layout-finger/tab_right_arrow.xml
similarity index 62%
copy from res/layout-finger/view_contact_name.xml
copy to res/layout-finger/tab_right_arrow.xml
index 126c69b..de69d8e 100644
--- a/res/layout-finger/view_contact_name.xml
+++ b/res/layout-finger/tab_right_arrow.xml
@@ -14,15 +14,14 @@
limitations under the License.
-->
-<!-- In the default locale, the "Name" field is a single TextView -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/name"
- android:layout_width="0dip"
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/arrow"
+ android:layout_width="32dip"
+ android:layout_height="37dip"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
android:layout_weight="1"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:shadowColor="#BB000000"
- android:shadowRadius="2.75"
- android:maxLines="2"
- android:ellipsize="end"
+ android:background="@drawable/tab_indicator_bg"
+ android:scaleType="centerInside"
+ android:src="@drawable/tab_right_arrow"
/>
diff --git a/res/layout-finger/view_contact_name.xml b/res/layout-finger/total_contacts.xml
similarity index 64%
rename from res/layout-finger/view_contact_name.xml
rename to res/layout-finger/total_contacts.xml
index 126c69b..12badb6 100644
--- a/res/layout-finger/view_contact_name.xml
+++ b/res/layout-finger/total_contacts.xml
@@ -4,9 +4,9 @@
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.
@@ -14,15 +14,14 @@
limitations under the License.
-->
-<!-- In the default locale, the "Name" field is a single TextView -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/name"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:shadowColor="#BB000000"
- android:shadowRadius="2.75"
- android:maxLines="2"
- android:ellipsize="end"
- />
+ android:id="@+id/totalContactsText"
+ android:layout_width="fill_parent"
+ android:layout_height="25dip"
+ android:textColor="#ffbfbfbf"
+ android:textSize="14sp"
+ android:textStyle="normal"
+ android:background="@drawable/infobar_dark"
+ android:paddingLeft="7dp"
+ android:gravity="center"
+/>
\ No newline at end of file
diff --git a/res/layout-finger/twelve_key_dialer.xml b/res/layout-finger/twelve_key_dialer.xml
index 071ca57..bd2c7a8 100644
--- a/res/layout-finger/twelve_key_dialer.xml
+++ b/res/layout-finger/twelve_key_dialer.xml
@@ -4,9 +4,9 @@
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.
@@ -20,51 +20,41 @@
android:layout_height="fill_parent"
android:orientation="vertical"
>
- <LinearLayout android:id="@+id/digitsAndBackspace"
+
+ <!-- Text field above the keypad where the digits are displayed.
+ It's type is set to NULL (to disable the IME keyboard) in the
+ java code.
+ -->
+ <!-- TODO: Use a textAppearance to control the display of the number -->
+ <EditText android:id="@+id/digits"
android:layout_width="fill_parent"
- android:layout_height="66px"
- android:layout_marginTop="3px"
- android:layout_marginBottom="5px"
- android:layout_marginLeft="3px"
- android:layout_marginRight="3px"
- android:orientation="horizontal"
- >
-
- <EditText android:id="@+id/digits"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="66px"
- android:maxLines="1"
- android:scrollHorizontally="true"
- android:textSize="28sp"
- android:freezesText="true"
- android:background="@drawable/btn_dial_textfield"
- android:textColor="@color/dialer_button_text"
- android:focusableInTouchMode="false"
- android:nextFocusRight="@+id/backspace"
- />
-
- <ImageButton android:id="@+id/backspace"
- style="@android:style/Widget.Button.Inset"
- android:layout_width="wrap_content"
- android:layout_height="66px"
- android:background="@drawable/btn_dial_delete"
- android:src="@drawable/ic_delete_phone_number"
- android:gravity="center"
- />
-
- </LinearLayout>
+ android:layout_height="67dip"
+ android:gravity="center"
+ android:maxLines="1"
+ android:scrollHorizontally="true"
+ android:textSize="33sp"
+ android:freezesText="true"
+ android:background="@drawable/btn_dial_textfield"
+ android:textColor="@color/dialer_button_text"
+ android:focusableInTouchMode="true"
+ android:editable="true"
+ android:cursorVisible="false"
+ android:layout_weight="0"
+ />
<!-- Keypad section -->
<include layout="@layout/dialpad" />
+ <!-- Horizontal row of buttons (Voicemail + DialButton + Delete.) -->
+ <include layout="@layout/voicemail_dial_delete" />
+
<!-- "Dialpad chooser" UI, shown only when the user brings up the
Dialer while a call is already in progress.
When this UI is visible, the other Dialer elements
(the textfield/button and the dialpad) are hidden. -->
<ListView android:id="@+id/dialpadChooser"
android:layout_width="fill_parent"
- android:layout_height="1dp"
+ android:layout_height="1dip"
android:layout_weight="1"
/>
diff --git a/res/layout-finger/view_contact.xml b/res/layout-finger/view_contact.xml
deleted file mode 100644
index 4a0f252..0000000
--- a/res/layout-finger/view_contact.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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,
- 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical"
->
-
- <LinearLayout android:id="@+id/banner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:background="@android:drawable/title_bar_tall"
- android:paddingRight="5dip"
- android:gravity="center_vertical"
- >
-
- <ImageView android:id="@+id/photo"
- style="?android:attr/imageWellStyle"
- android:layout_width="78dip"
- android:layout_height="78dip"
- android:layout_marginRight="7dip"
- android:layout_marginLeft="2dip"
- android:scaleType="fitCenter"
- android:background="@drawable/btn_contact_picture"
- />
-
- <!-- "Name" field is locale-specific. -->
- <include layout="@layout/view_contact_name"/>
-
- <CheckBox android:id="@+id/star"
- style="?android:attr/starStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- />
-
- </LinearLayout>
-
- <FrameLayout
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- >
-
- <View
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/title_bar_shadow"
- />
-
- <ListView android:id="@android:id/list"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:scrollbarStyle="outsideOverlay"
- />
- </FrameLayout>
-</LinearLayout>
diff --git a/res/layout-finger/voicemail_dial_delete.xml b/res/layout-finger/voicemail_dial_delete.xml
new file mode 100644
index 0000000..910aaff
--- /dev/null
+++ b/res/layout-finger/voicemail_dial_delete.xml
@@ -0,0 +1,62 @@
+<?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.
+-->
+
+<!-- Horizontal row of buttons (Voicemail + DialButton + Delete.) -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/voicemailAndDialAndDelete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="6dip"
+ android:layout_weight="1"
+ android:orientation="horizontal">
+
+ <!-- Onscreen "Voicemail" button.
+ The width is 75 (from the mocks) + 12 of padding from the
+ 9patch, total is 87.
+ -->
+ <ImageButton android:id="@+id/voicemailButton"
+ android:layout_width="87dip"
+ android:layout_height="50dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_voicemail"
+ android:src="@drawable/ic_dial_action_voice_mail" />
+
+ <!-- Onscreen "Dial" button, used on all platforms by
+ default. Its usage can be disabled using resources (see
+ config.xml.) -->
+ <ImageButton android:id="@+id/dialButton"
+ android:layout_width="116dip"
+ android:layout_height="50dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_action"
+ android:src="@drawable/ic_dial_action_call" />
+
+ <!-- Onscreen "Backspace/Delete" button
+ The width is 75 (from the mocks) + 12 of padding from the
+ 9patch, total is 87.
+ -->
+ <ImageButton android:id="@+id/deleteButton"
+ android:layout_width="87dip"
+ android:layout_height="50dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_delete"
+ android:src="@drawable/ic_dial_action_delete" />
+</LinearLayout>
+
diff --git a/res/layout-land-finger/twelve_key_dialer.xml b/res/layout-land-finger/twelve_key_dialer.xml
index 2b436b8..92906ba 100644
--- a/res/layout-land-finger/twelve_key_dialer.xml
+++ b/res/layout-land-finger/twelve_key_dialer.xml
@@ -4,9 +4,9 @@
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.
@@ -20,44 +20,29 @@
android:layout_height="fill_parent"
android:orientation="vertical"
>
- <LinearLayout android:id="@+id/digitsAndBackspace"
+
+ <!-- Text field above the keypad where the digits are displayed.
+ It's type is set to PHONE (to put the keyboard in the right
+ config) in the java code.
+ -->
+ <!-- TODO: Use a textAppearance to control the display of the number -->
+ <EditText android:id="@+id/digits"
android:layout_width="fill_parent"
- android:layout_height="66px"
- android:addStatesFromChildren="true"
- android:gravity="center_vertical"
- android:baselineAligned="false"
- android:layout_marginTop="3px"
- android:layout_marginBottom="5px"
- android:layout_marginLeft="3px"
- android:layout_marginRight="3px"
- >
+ android:layout_height="66dip"
+ android:layout_marginBottom="50dip"
+ android:layout_marginTop="1dip"
+ android:gravity="center"
+ android:maxLines="1"
+ android:scrollHorizontally="true"
+ android:textSize="28sp"
+ android:freezesText="true"
+ android:background="@drawable/btn_dial_textfield"
+ android:textColor="@color/dialer_button_text"
+ android:hint="@string/dialerKeyboardHintText"
+ />
- <EditText android:id="@+id/digits"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="66px"
- android:maxLines="1"
- android:scrollHorizontally="true"
- android:textSize="28sp"
- android:freezesText="true"
- android:background="@drawable/btn_dial_textfield"
- android:textColor="@color/dialer_button_text"
- android:hint="@string/dialerKeyboardHintText"
- />
-
- <!--
- The button goes at the right.
- -->
- <ImageButton android:id="@+id/backspace"
- style="@android:style/Widget.Button.Inset"
- android:src="@drawable/ic_delete_phone_number"
- android:layout_width="wrap_content"
- android:layout_height="66px"
- android:background="@drawable/btn_dial_delete"
- android:gravity="center"
- />
-
- </LinearLayout>
+ <!-- Horizontal row of buttons (Voicemail + DialButton + Delete.) -->
+ <include layout="@layout/voicemail_dial_delete" />
<!-- "Dialpad chooser" UI, shown only when the user brings up the
Dialer while a call is already in progress.
diff --git a/res/layout-long-finger/dialpad.xml b/res/layout-long-finger/dialpad.xml
new file mode 100644
index 0000000..9fea6d2
--- /dev/null
+++ b/res/layout-long-finger/dialpad.xml
@@ -0,0 +1,139 @@
+<?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.
+-->
+
+<!-- Dialpad in the Contact app.
+ Tall screen version with taller buttons.
+ -->
+
+<com.android.contacts.ButtonGridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/dialpad"
+ android:paddingLeft="7dp"
+ android:paddingRight="7dp"
+ android:paddingTop="6dp"
+ android:paddingBottom="6dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="1"
+>
+ <ImageButton android:id="@+id/one"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_1_no_vm"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_one"
+ />
+
+ <ImageButton android:id="@+id/two"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_2"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_two"
+ />
+
+ <ImageButton android:id="@+id/three"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_3"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_three"
+ />
+
+ <ImageButton android:id="@+id/four"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_4"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_four"
+ />
+
+ <ImageButton android:id="@+id/five"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_5"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_five"
+ />
+
+ <ImageButton android:id="@+id/six"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_6"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_six"
+ />
+
+ <ImageButton android:id="@+id/seven"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_7"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_seven"
+ />
+
+ <ImageButton android:id="@+id/eight"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_8"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_eight"
+ />
+
+ <ImageButton android:id="@+id/nine"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_9"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_nine"
+ />
+
+ <ImageButton android:id="@+id/star"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_star"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_star"
+ />
+
+ <ImageButton android:id="@+id/zero"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_0"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_zero"
+ />
+
+ <ImageButton android:id="@+id/pound"
+ android:layout_width="88dp"
+ android:layout_height="58dp"
+ android:src="@drawable/dial_num_pound"
+ android:background="@drawable/btn_dial"
+ android:soundEffectsEnabled="false"
+ android:contentDescription="@string/description_image_button_pound"
+ />
+</com.android.contacts.ButtonGridLayout>
diff --git a/res/layout-long-finger/twelve_key_dialer.xml b/res/layout-long-finger/twelve_key_dialer.xml
new file mode 100644
index 0000000..07771cc
--- /dev/null
+++ b/res/layout-long-finger/twelve_key_dialer.xml
@@ -0,0 +1,61 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/top"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+>
+
+ <!-- Text field above the keypad where the digits are displayed.
+ It's type is set to NULL (to disable the IME keyboard) in the
+ java code.
+ -->
+ <!-- TODO: Use a textAppearance to control the display of the number -->
+ <EditText android:id="@+id/digits"
+ android:layout_width="fill_parent"
+ android:layout_height="74dip"
+ android:gravity="center"
+ android:maxLines="1"
+ android:scrollHorizontally="true"
+ android:textSize="34sp"
+ android:freezesText="true"
+ android:background="@drawable/btn_dial_textfield"
+ android:textColor="@color/dialer_button_text"
+ android:focusableInTouchMode="true"
+ android:editable="true"
+ android:cursorVisible="false"
+ android:layout_weight="0"
+ />
+
+ <!-- Keypad section -->
+ <include layout="@layout/dialpad" />
+
+ <!-- Horizontal row of buttons (Voicemail + DialButton + Delete.) -->
+ <include layout="@layout/voicemail_dial_delete" />
+
+ <!-- "Dialpad chooser" UI, shown only when the user brings up the
+ Dialer while a call is already in progress.
+ When this UI is visible, the other Dialer elements
+ (the textfield/button and the dialpad) are hidden. -->
+ <ListView android:id="@+id/dialpadChooser"
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:layout_weight="1"
+ />
+
+</LinearLayout>
diff --git a/res/layout-long-finger/voicemail_dial_delete.xml b/res/layout-long-finger/voicemail_dial_delete.xml
new file mode 100644
index 0000000..8c42e65
--- /dev/null
+++ b/res/layout-long-finger/voicemail_dial_delete.xml
@@ -0,0 +1,63 @@
+<?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.
+-->
+
+<!-- Horizontal row of buttons (Voicemail + DialButton + Delete.)
+ Tall screen version with taller buttons.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/voicemailAndDialAndDelete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="2.5"
+ android:orientation="horizontal">
+
+ <!-- Onscreen "Voicemail" button.
+ The width is 75 (from the mocks) + 12 of padding from the
+ 9patch, total is 87.
+ -->
+ <ImageButton android:id="@+id/voicemailButton"
+ android:layout_width="87dip"
+ android:layout_height="58dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_voicemail"
+ android:src="@drawable/ic_dial_action_voice_mail" />
+
+ <!-- Onscreen "Dial" button, used on all platforms by
+ default. Its usage can be disabled using resources (see
+ config.xml.) -->
+ <ImageButton android:id="@+id/dialButton"
+ android:layout_width="116dip"
+ android:layout_height="58dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_action"
+ android:src="@drawable/ic_dial_action_call" />
+
+ <!-- Onscreen "Backspace/Delete" button
+ The width is 75 (from the mocks) + 12 of padding from the
+ 9patch, total is 87.
+ -->
+ <ImageButton android:id="@+id/deleteButton"
+ android:layout_width="87dip"
+ android:layout_height="58dip"
+ android:layout_gravity="center_vertical"
+ android:state_enabled="false"
+ android:background="@drawable/btn_dial_delete"
+ android:src="@drawable/ic_dial_action_delete" />
+</LinearLayout>
+
diff --git a/res/layout-long-land-finger/twelve_key_dialer.xml b/res/layout-long-land-finger/twelve_key_dialer.xml
new file mode 100644
index 0000000..18c9a0f
--- /dev/null
+++ b/res/layout-long-land-finger/twelve_key_dialer.xml
@@ -0,0 +1,57 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/top"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+>
+
+ <!-- Text field above the keypad where the digits are displayed.
+ It's type is set to PHONE (to put the keyboard in the right
+ config) in the java code.
+ -->
+ <!-- TODO: Use a textAppearance to control the display of the number -->
+ <EditText android:id="@+id/digits"
+ android:layout_width="fill_parent"
+ android:layout_height="74dip"
+ android:layout_marginBottom="30dip"
+ android:layout_marginTop="1dip"
+ android:gravity="center"
+ android:maxLines="1"
+ android:scrollHorizontally="true"
+ android:textSize="34sp"
+ android:freezesText="true"
+ android:background="@drawable/btn_dial_textfield"
+ android:textColor="@color/dialer_button_text"
+ android:hint="@string/dialerKeyboardHintText"
+ />
+
+ <!-- Horizontal row of buttons (Voicemail + DialButton + Delete.) -->
+ <include layout="@layout/voicemail_dial_delete" />
+
+ <!-- "Dialpad chooser" UI, shown only when the user brings up the
+ Dialer while a call is already in progress.
+ When this UI is visible, the other Dialer elements
+ (the textfield and button) are hidden. -->
+ <ListView android:id="@+id/dialpadChooser"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:footerDividersEnabled="true"
+ />
+
+</LinearLayout>
diff --git a/res/layout/act_display_groups.xml b/res/layout/act_display_groups.xml
new file mode 100644
index 0000000..5ee93e7
--- /dev/null
+++ b/res/layout/act_display_groups.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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,
+ 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:fillViewport="true">
+
+ <ExpandableListView
+ android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1" />
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ style="@android:style/ButtonBar">
+
+ <Button
+ android:id="@+id/btn_done"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/menu_done" />
+
+ <Button
+ android:id="@+id/btn_discard"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/menu_doNotSave" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/act_edit.xml b/res/layout/act_edit.xml
new file mode 100644
index 0000000..e56ec20
--- /dev/null
+++ b/res/layout/act_edit.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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,
+ 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+>
+
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:layout_weight="1"
+ android:fillViewport="true"
+ >
+
+ <LinearLayout android:id="@+id/editors"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ />
+
+ </ScrollView>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ style="@android:style/ButtonBar"
+ >
+
+ <Button android:id="@+id/btn_done"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/menu_done"
+ />
+
+ <Button android:id="@+id/btn_discard"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/menu_doNotSave"
+ />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/item_contact_editor.xml b/res/layout/item_contact_editor.xml
new file mode 100644
index 0000000..a7d5df5
--- /dev/null
+++ b/res/layout/item_contact_editor.xml
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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,
+ 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.
+-->
+
+<!-- placed inside act_edit as tabcontent -->
+<com.android.contacts.ui.widget.ContactEditorView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+>
+
+ <!-- Left side color bar -->
+ <ImageView
+ android:id="@+id/color_bar"
+ android:layout_width="4dip"
+ android:layout_height="fill_parent"
+ android:visibility="gone"
+ />
+
+ <!-- The content -->
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ >
+
+ <!-- Account info header -->
+ <RelativeLayout android:id="@+id/header"
+ android:layout_height="64dip"
+ android:layout_width="fill_parent"
+ >
+
+ <ImageView android:id="@+id/header_color_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="4dip"
+ android:layout_marginBottom="5dip"
+ android:background="@color/edit_divider"
+ />
+
+ <ImageView android:id="@+id/header_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:layout_centerVertical="true"
+ android:layout_below="@id/header_color_bar"
+ />
+
+ <TextView android:id="@+id/header_account_type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@+id/header_icon"
+ android:layout_alignTop="@id/header_icon"
+ android:layout_marginTop="-4dip"
+
+ android:textSize="24sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"
+ />
+
+ <TextView android:id="@+id/header_account_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@+id/header_icon"
+ android:layout_alignBottom="@+id/header_icon"
+ android:layout_marginBottom="2dip"
+
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"
+ />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:layout_alignParentBottom="true"
+
+ android:background="?android:attr/listDivider"
+ />
+
+ </RelativeLayout>
+
+ <FrameLayout
+ android:id="@+id/stub_photo"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="12dip"
+ android:paddingTop="10dip">
+
+ <include
+ android:id="@+id/edit_photo"
+ layout="@layout/item_photo_editor" />
+
+ </FrameLayout>
+
+ <include
+ android:id="@+id/edit_name"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/stub_photo"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="4dip"
+ layout="@layout/item_generic_editor" />
+
+ <TextView android:id="@+id/read_only_name"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_marginLeft="10dip"
+
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
+
+ <LinearLayout
+ android:id="@+id/sect_general"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ />
+
+ <View android:id="@+id/head_secondary_divider"
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="?android:attr/listDivider" />
+
+ <TextView
+ android:id="@+id/head_secondary"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:text="@string/edit_secondary_collapse"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/kind_title"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:focusable="true"
+ android:clickable="true"
+ android:paddingLeft="10dip"
+ android:drawablePadding="10dip" />
+
+ <LinearLayout
+ android:id="@+id/sect_secondary"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" />
+
+ <TextView
+ android:id="@+id/edit_read_only"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:layout_marginBottom="10dip"
+ android:layout_marginLeft="10dip"
+
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:drawableLeft="@android:drawable/ic_dialog_alert"
+ android:drawablePadding="10dip"
+ />
+
+ </LinearLayout>
+
+</com.android.contacts.ui.widget.ContactEditorView>
diff --git a/res/drawable-finger/dial_num_1.xml b/res/layout/item_editor_field.xml
similarity index 65%
copy from res/drawable-finger/dial_num_1.xml
copy to res/layout/item_editor_field.xml
index 48737b2..1e77068 100644
--- a/res/drawable-finger/dial_num_1.xml
+++ b/res/layout/item_editor_field.xml
@@ -4,9 +4,9 @@
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.
@@ -14,12 +14,7 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/dial_num_1_blk" />
- <item android:state_focused="true"
- android:drawable="@drawable/dial_num_1_blk" />
- <item
- android:drawable="@drawable/dial_num_1_wht" />
-</selector>
-
+<EditText
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
diff --git a/res/layout/item_generic_editor.xml b/res/layout/item_generic_editor.xml
new file mode 100644
index 0000000..01fa980
--- /dev/null
+++ b/res/layout/item_generic_editor.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<com.android.contacts.ui.widget.GenericEditorView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:baselineAligned="false"
+ android:paddingRight="?android:attr/scrollbarSize">
+
+ <Button
+ android:id="@+id/edit_label"
+ android:layout_width="100dip"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:gravity="left|center_vertical" />
+
+ <ImageButton
+ android:id="@+id/edit_delete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ style="@style/MinusButton" />
+
+ <LinearLayout
+ android:id="@+id/edit_fields"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dip"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_toRightOf="@id/edit_label"
+ android:layout_toLeftOf="@id/edit_delete"
+ android:orientation="vertical"
+ android:baselineAligned="false"
+ android:gravity="center_vertical" />
+
+ <ImageButton
+ android:id="@+id/edit_more"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_alignBottom="@id/edit_fields"
+ android:visibility="gone"
+ style="@style/MoreButton" />
+
+</com.android.contacts.ui.widget.GenericEditorView>
diff --git a/res/layout/item_kind_section.xml b/res/layout/item_kind_section.xml
new file mode 100644
index 0000000..73912aa
--- /dev/null
+++ b/res/layout/item_kind_section.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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 body surrounding all editors for a specific kind -->
+
+<com.android.contacts.ui.widget.KindSectionView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:orientation="vertical">
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/listDivider" />
+
+ <LinearLayout
+ android:id="@+id/kind_header"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="14dip"
+ android:layout_marginTop="2dip"
+ android:layout_marginBottom="2dip"
+ android:layout_marginRight="?android:attr/scrollbarSize"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:focusable="true"
+ android:clickable="true">
+
+ <TextView
+ android:id="@+id/kind_title"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/kind_title"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:duplicateParentState="true"
+ style="@style/PlusButton" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/kind_editors"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="6dip"
+ android:orientation="vertical" />
+
+</com.android.contacts.ui.widget.KindSectionView>
diff --git a/res/layout/item_photo_editor.xml b/res/layout/item_photo_editor.xml
new file mode 100644
index 0000000..7544439
--- /dev/null
+++ b/res/layout/item_photo_editor.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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,
+ 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.
+-->
+
+<com.android.contacts.ui.widget.PhotoEditorView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/edit_photo_size"
+ android:layout_height="@dimen/edit_photo_size"
+ android:clickable="true"
+ android:focusable="true"
+ android:src="@drawable/ic_menu_add_picture"
+ android:cropToPadding="true"
+ android:scaleType="center"
+ android:background="@drawable/btn_contact_picture"
+ android:gravity="center" />
diff --git a/res/layout/item_read_only_contact_editor.xml b/res/layout/item_read_only_contact_editor.xml
new file mode 100644
index 0000000..0b1dc14
--- /dev/null
+++ b/res/layout/item_read_only_contact_editor.xml
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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,
+ 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.
+-->
+
+<!-- placed inside act_edit as tabcontent -->
+<com.android.contacts.ui.widget.ReadOnlyContactEditorView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+>
+
+ <!-- Left side color bar -->
+ <ImageView
+ android:id="@+id/color_bar"
+ android:layout_width="4dip"
+ android:layout_height="fill_parent"
+ android:visibility="gone"
+ />
+
+ <!-- The content -->
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ >
+
+ <!-- Account info header -->
+ <RelativeLayout android:id="@+id/header"
+ android:layout_height="64dip"
+ android:layout_width="fill_parent"
+ >
+
+ <ImageView android:id="@+id/header_color_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="4dip"
+ android:layout_marginBottom="5dip"
+ android:background="@color/edit_divider"
+ />
+
+ <ImageView android:id="@+id/header_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:layout_centerVertical="true"
+ android:layout_below="@id/header_color_bar"
+ />
+
+ <TextView android:id="@+id/header_account_type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@+id/header_icon"
+ android:layout_alignTop="@id/header_icon"
+ android:layout_marginTop="-4dip"
+
+ android:textSize="24sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"
+ />
+
+ <TextView android:id="@+id/header_account_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@+id/header_icon"
+ android:layout_alignBottom="@+id/header_icon"
+ android:layout_marginBottom="2dip"
+
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"
+ />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:layout_alignParentBottom="true"
+
+ android:background="?android:attr/listDivider"
+ />
+
+ </RelativeLayout>
+
+ <FrameLayout
+ android:id="@+id/stub_photo"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="12dip"
+ android:paddingTop="10dip">
+
+ <include
+ android:id="@+id/edit_photo"
+ layout="@layout/item_photo_editor" />
+
+ </FrameLayout>
+
+ <TextView android:id="@+id/read_only_name"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_marginLeft="10dip"
+
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="?android:attr/listDivider"
+ />
+
+ <TextView
+ android:id="@+id/read_only_warning"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="13dip"
+ android:layout_marginBottom="13dip"
+ android:layout_marginLeft="13dip"
+
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:drawableLeft="@android:drawable/ic_dialog_alert"
+ android:drawablePadding="10dip"
+ />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="?android:attr/listDivider"
+ />
+
+ <LinearLayout android:id="@+id/sect_general"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ />
+ </LinearLayout>
+
+</com.android.contacts.ui.widget.ReadOnlyContactEditorView>
diff --git a/res/layout/item_read_only_field.xml b/res/layout/item_read_only_field.xml
new file mode 100644
index 0000000..a0b20c4
--- /dev/null
+++ b/res/layout/item_read_only_field.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+
+ android:orientation="vertical"
+>
+
+ <TextView android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginTop="2dip"
+
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:singleLine="true"
+ />
+
+ <TextView android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:layout_marginLeft="10dip"
+ android:layout_marginBottom="4dip"
+
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:singleLine="true"
+ />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+
+ android:background="?android:attr/listDivider"
+ />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/menu/edit.xml b/res/menu/edit.xml
new file mode 100644
index 0000000..6fafbcf
--- /dev/null
+++ b/res/menu/edit.xml
@@ -0,0 +1,49 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/menu_done"
+ android:alphabeticShortcut="\n"
+ android:icon="@android:drawable/ic_menu_save"
+ android:title="@string/menu_done" />
+
+ <item
+ android:id="@+id/menu_discard"
+ android:alphabeticShortcut="q"
+ android:icon="@android:drawable/ic_menu_close_clear_cancel"
+ android:title="@string/menu_doNotSave" />
+
+ <item
+ android:id="@+id/menu_add"
+ android:icon="@android:drawable/ic_menu_add"
+ android:title="@string/menu_newContact" />
+
+ <item
+ android:id="@+id/menu_delete"
+ android:icon="@android:drawable/ic_menu_delete"
+ android:title="@string/menu_deleteContact" />
+
+ <item
+ android:id="@+id/menu_split"
+ android:icon="@drawable/ic_menu_split"
+ android:title="@string/menu_splitAggregate" />
+
+ <item
+ android:id="@+id/menu_join"
+ android:icon="@drawable/ic_menu_merge"
+ android:title="@string/menu_joinAggregate" />
+</menu>
diff --git a/res/menu/list.xml b/res/menu/list.xml
new file mode 100644
index 0000000..b8f9b76
--- /dev/null
+++ b/res/menu/list.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/menu_search"
+ android:icon="@android:drawable/ic_menu_search"
+ android:title="@string/menu_search" />
+
+ <item
+ android:id="@+id/menu_add"
+ android:icon="@android:drawable/ic_menu_add"
+ android:title="@string/menu_newContact"
+ android:alphabeticShortcut="n" />
+
+ <item
+ android:id="@+id/menu_display_groups"
+ android:icon="@*android:drawable/ic_menu_allfriends"
+ android:title="@string/menu_displayGroup" />
+
+ <item
+ android:id="@+id/menu_accounts"
+ android:icon="@drawable/ic_menu_account_list"
+ android:title="@string/menu_accounts" />
+
+ <item
+ android:id="@+id/menu_import_export"
+ android:icon="@drawable/ic_menu_import_export"
+ android:title="@string/menu_import_export" />
+
+</menu>
diff --git a/res/menu/view.xml b/res/menu/view.xml
new file mode 100644
index 0000000..428434d
--- /dev/null
+++ b/res/menu/view.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/menu_edit"
+ android:icon="@android:drawable/ic_menu_edit"
+ android:title="@string/menu_editContact"
+ android:alphabeticShortcut="e" />
+
+ <item
+ android:id="@+id/menu_share"
+ android:icon="@android:drawable/ic_menu_share"
+ android:title="@string/menu_share"
+ android:alphabeticShortcut="s" />
+
+ <item
+ android:id="@+id/menu_options"
+ android:icon="@drawable/ic_menu_mark"
+ android:title="@string/menu_contactOptions" />
+
+ <item
+ android:id="@+id/menu_delete"
+ android:icon="@android:drawable/ic_menu_delete"
+ android:title="@string/menu_deleteContact" />
+
+</menu>
diff --git a/res/values-cs/config.xml b/res/values-cs/config.xml
deleted file mode 100644
index 07b3c7e..0000000
--- a/res/values-cs/config.xml
+++ /dev/null
@@ -1,28 +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">
- <!-- no translation found for config_export_vcard_type (9145748078116159716) -->
- <skip />
- <string name="config_export_dir" msgid="222182743639478636">"/sdcard"</string>
- <!-- no translation found for config_export_file_prefix (3022868431158658122) -->
- <skip />
- <!-- no translation found for config_export_file_suffix (16505844221142195) -->
- <skip />
- <string name="config_export_file_extension" msgid="1758878818611339161">"vcf"</string>
- <!-- no translation found for config_export_extensions_to_consider (5095044502091950623) -->
- <skip />
-</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index b7cc16e..1bd32b5 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Kontakty"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Vytáčení"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefon"</string>
<string name="shortcutContact" msgid="749243779392912958">"Kontakt"</string>
- <string name="shortcutDialContact" msgid="7165340343023469996">"Přímé vytáčení"</string>
- <string name="shortcutMessageContact" msgid="3025782962770298900">"Přímá zpráva"</string>
+ <string name="shortcutDialContact" msgid="746622101599186779">"Přímé vytáčení"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Přímá zpráva"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"Výběr zkratky kontaktu"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"Výběr čísla pro hovor"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Výběr čísla pro zprávu"</string>
@@ -40,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Zobrazit čárový kód"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Upravit kontakt"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Smazat kontakt"</string>
- <string name="menu_call" msgid="7359207953236681606">"Volat"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Odeslat SMS nebo MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Volat kontakt"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Odeslat zprávu kontaktu"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Odeslat e-mail"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Adresa na mapě"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Nastavit jako výchozí číslo"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Nastavit jako výchozí e-mail"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Oddělit"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Oddělit kontakt"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Kontakty byly odděleny"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Oddělit kontakt"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Opravdu chcete tento kontakt rozdělit do více kontaktů? Pro každou připojenou kontaktní informaci bude vytvořen samostatný kontakt."</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Spojit"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Zobrazit zdroje"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Skrýt zdroje"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Připojit kontakt"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Spojit kontakty"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Vyberte kontakt, který chcete spojit s kontaktem <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Zobrazit všechny kontakty"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Navrhované kontakty"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Všechny kontakty"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Kontakty byly spojeny"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Možnosti"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Možnosti"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Smazat"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Z účtů pouze pro čtení není možné kontakty mazat, můžete je však v seznamech kontaktů skrýt."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Tento kontakt obsahuje informace z několika účtů. Informace z účtů pouze pro čtení budou v seznamech kontaktů skryty, ale nebudou smazány."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Smazáním tohoto kontaktu smažete informace z více účtů."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Tento kontakt bude smazán."</string>
<string name="menu_done" msgid="796017761764190697">"Hotovo"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Vrátit"</string>
@@ -55,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Foneticky"</string>
<string name="label_notes" msgid="8337354953278341042">"Poznámky"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Vyzváněcí tón"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Skupiny"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Upravit skupiny"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Jméno a příjmení"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Jméno (foneticky)"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Společnost"</string>
@@ -64,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Telefonní číslo"</string>
<string name="ghostData_email" msgid="6184537075551565919">"E-mailová adresa"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Poštovní adresa"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Zobrazit skupinu"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Kontakt neexistuje."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Vytvořit nový kontakt"</string>
<string name="selectLabel" msgid="4255424123394910733">"Vyberte štítek"</string>
@@ -80,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"V telefonu nejsou žádné fotografie."</string>
<string name="attachToContact" msgid="8820530304406066714">"Ikona kontaktu"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Název vlastního štítku"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Zobrazit skupinu"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Možnosti zobrazení"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Možnosti zobrazení"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Upravit synchronizaci"</string>
<string name="importFromSim" msgid="8383900146531125319">"Importovat kontakty"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Odesílat hovory přímo do hlasové pošty"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Hovory jsou přesměrovány přímo do hlasové schránky."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Výchozí"</string>
<string name="addPicture" msgid="1594679312161537678">"Přidat ikonu"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Změnit ikonu"</string>
<string name="removePicture" msgid="3041230993155966350">"Odstranit ikonu"</string>
<string name="noContacts" msgid="8579310973261953559">"Žádné kontakty."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Nebyly nalezeny žádné odpovídající kontakty."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Ke kontaktům nejsou přiřazena žádná telefonní čísla."</string>
<string name="noFavorites" msgid="812766386743315815">"Žádné oblíbené položky."</string>
<string name="select_group_title" msgid="7955698611959835612">"Skupiny"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Skupina <xliff:g id="GROUPNAME">%s</xliff:g> je prázdná."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Všechny kontakty"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Pouze kontakty s telefonními čísly"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Zobrazit pouze kontakty s telefonními čísly"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Zvolte kontakty, které budou zobrazeny"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"Počet kontaktů: <xliff:g id="COUNT">%0$d</xliff:g>"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"Počet kontaktů: <xliff:g id="COUNT_0">%1$d</xliff:g>, z toho <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> s telefonními čísly"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Synchronizovat všechny kontakty"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Moje kontakty"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Moje kontakty"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Kontakty s telefonním číslem"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Označené hvězdičkou v systému Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Ukládání kontaktu…"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Ukládání možností zobrazení…"</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Kontakt byl vytvořen."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Kontakt byl uložen."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Chyba, změny kontaktu nelze uložit."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Vytočit číslo"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Telefonní čísla"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Odeslat SMS nebo MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Odeslat zprávu"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Odeslat e-mail"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"E-mailové adresy"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Odeslat zprávu chatu"</string>
@@ -110,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Adresa na mapě"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Poštovní adresa"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organizace"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Skupiny"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Ostatní informace"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Další možnosti"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Další"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Zobrazuje se 1 kontakt s telefonním číslem"</item>
+ <item quantity="other" msgid="6133262880804110289">"Počet zobrazených kontaktů s telefonními čísly: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Žádné kontakty s telefonními čísly nejsou viditelné"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Zobrazuje se 1 kontakt"</item>
+ <item quantity="other" msgid="2865867557378939630">"Počet zobrazených kontaktů: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Žádné kontakty nejsou viditelné"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"Nalezen 1 kontakt"</item>
+ <item quantity="other" msgid="7752927996850263152">"Počet nalezených kontaktů: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Kontakt nebyl nalezen"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Společenské"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakty"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Oblíbené"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Vytáčení"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Hovory"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Všechny kontakty"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Kontakty označené hvězdičkou"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Kontakty s telefonními čísly"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Odeslat zprávu SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Odeslat textovou zprávu"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Volat kontakt <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Před voláním upravit číslo"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Přidat mezi kontakty"</string>
@@ -128,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Vymazat hovory"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Záznam hovorů je prázdný."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Hlasová schránka"</string>
<string name="unknown" msgid="740067747858270469">"Neznámé číslo"</string>
<string name="private_num" msgid="6374339738119166953">"Soukromé číslo"</string>
@@ -137,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Načítání z karty SIM..."</string>
<string name="simContacts_title" msgid="27341688347689769">"Kontakty na kartě SIM"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Synchronizujte své kontakty Google!"</font>" "\n"Po synchronizaci telefonu budete mít kontaktní informace vždy u sebe."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Nemáte žádné kontakty."\n\n"Chcete-li kontakty přidat, stiskněte tlačítko "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" a vyberte možnost:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Nový kontakt"</b></font>", pokud chcete vytvořit nový kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importovat kontakty"</b></font>", pokud chcete přidat kontakty ze své karty SIM"\n</li>"."</string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Nemáte žádné kontakty."\n\n"Chcete-li přidat kontakty, stiskněte tlačítko "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" a vyberte možnost:"\n\n<li><font fgcolor="#ffffffff"><b>"Upravit synchronizované skupiny"</b></font>", pokud chcete přidat kontakty z nového nebo existujícího účtu Google"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nový kontakt"</b></font>", pokud chcete vytvořit nový kontakt"\n</li>\n<li><font fgcolor="#ffffffff"><b>"Importovat kontakty"</b></font>", pokud chcete přidat kontakty ze své karty SIM"\n</li>"."</string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Nemáte žádné kontakty, které by bylo možné zobrazit."\n\n"Chcete-li přidat kontakty, stiskněte tlačítko "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" a dotkněte se položky:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Účty"</b></font>", pokud chcete přidat nebo nakonfigurovat účet a kontakty v něm synchronizovat s telefonem;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nový kontakt"</b></font>", pokud chcete vytvořit úplně nový kontakt;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importovat nebo exportovat"</b></font>"."\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Nemáte žádné kontakty, které by bylo možné zobrazit. (Pokud jste právě přidali účet, může synchronizace kontaktů trvat několik minut.)"\n\n"Chcete-li přidat kontakty, stiskněte tlačítko "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" a dotkněte se položky:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Účty"</b></font>", pokud chcete přidat nebo nakonfigurovat účet a kontakty v něm synchronizovat s telefonem;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Možnosti zobrazení"</b></font>", pokud chcete změnit, které kontakty budou zobrazeny;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nový kontakt"</b></font>", pokud chcete vytvořit úplně nový kontakt;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importovat nebo exportovat"</b></font>"."\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Nemáte žádné kontakty, které by bylo možné zobrazit."\n\n"Chcete-li přidat kontakty, stiskněte tlačítko "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" a dotkněte se položky:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Účty"</b></font>", pokud chcete přidat nebo nakonfigurovat účet a kontakty v něm synchronizovat s telefonem;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nový kontakt"</b></font>", pokud chcete vytvořit úplně nový kontakt;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importovat nebo exportovat"</b></font>"."\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Nemáte žádné kontakty, které by bylo možné zobrazit. (Pokud jste právě přidali účet, může synchronizace kontaktů trvat několik minut.)"\n\n"Chcete-li přidat kontakty, stiskněte tlačítko "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" a dotkněte se položky:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Účty"</b></font>", pokud chcete přidat nebo nakonfigurovat účet a kontakty v něm synchronizovat s telefonem;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Možnosti zobrazení"</b></font>", pokud chcete změnit, které kontakty budou zobrazeny;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nový kontakt"</b></font>", pokud chcete vytvořit úplně nový kontakt;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importovat nebo exportovat"</b></font>"."\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Nemáte žádné oblíbené kontakty."\n\n"Přidání kontaktu do seznamu oblíbených:"\n\n" "<li>"Dotkněte se karty "<b>"Kontakty"</b>"."\n</li>" "\n<li>"Dotkněte se kontaktu, který chcete přidat mezi oblíbené."\n</li>" "\n<li>"Dotkněte se hvězdičky vedle jména kontaktu."\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Vyberte skupiny, které chcete synchronizovat"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Všechny kontakty"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Všechny kontakty"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"S hvězdičkou"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Telefony"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Použít dotykovou tónovou klávesnici"</string>
@@ -171,8 +232,9 @@
<string name="returnCall" msgid="8171961914203617813">"Zpětné volání"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> min <xliff:g id="SECONDS">%s</xliff:g> s"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Často volané"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Přidat kontakt"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Přidat kontakt"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Chcete přidat „<xliff:g id="EMAIL">%s</xliff:g>“ do kontaktů?"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Všechny"</string>
<string name="description_image_button_one" msgid="1740638037139856139">"jedna"</string>
<string name="description_image_button_two" msgid="5882638439003731308">"dvě"</string>
<string name="description_image_button_three" msgid="8709731759376015180">"tři"</string>
@@ -185,43 +247,176 @@
<string name="description_image_button_star" msgid="3365919907520767866">"hvězdička"</string>
<string name="description_image_button_zero" msgid="4133108949401820710">"nula"</string>
<string name="description_image_button_pound" msgid="3039765597595889230">"libra"</string>
- <string name="no_sdcard_title" msgid="6455416795090113715">"Žádná karta SD"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Nebyla zjištěna žádná karta SD"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Vyhledávání karty VCard"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Žádná karta SD"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Nebyla zjištěna žádná karta SD"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Vyhledávání karty vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Odkud chcete kontakty importovat?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"Karta SIM"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"Karta SD"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importovat všechny soubory VCard"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Importovat jeden soubor karty VCard"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Vyhledávání dat karty VCard na kartě VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Vyhledávání na kartě SD se nezdařilo"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Vyhledávání na kartě SD se nezdařilo"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importovat z karty SIM"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importovat z karty SD"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Exportovat na kartu SD"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importovat jeden soubor vCard"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importovat několik souborů vCard"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importovat všechny soubory vCard"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Vyhledávání dat karty vCard na kartě SD"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Vyhledávání na kartě SD se nezdařilo"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Vyhledávání na kartě SD se nezdařilo. (Důvod: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Chyba V/V"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Analýza karty VCard se nezdařila"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Na kartě SD nebyl nalezen žádný soubor karty VCard"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Pro daný výběr nebyla nalezena žádná položka karty VCard"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Výběr souboru VCard"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Vyberte soubor karty VCard k importu"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Čtení karty VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Čtení souborů karty VCard"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Probíhá import dat na kartě VCard"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Čtení dat karty VCard se nezdařilo"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"Data na kartě VCard nelze přečíst."\n"Důvod selhání: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Analýza karty vCard se z neznámého důvodu nezdařila."</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Analýza karty vCard se nezdařila. Přestože se zřejmě jedná o správný formát, aktuální implementace jej nepodporuje."</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Na kartě SD nebyl nalezen žádný soubor vCard"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Ve vašem výběru nebyla nalezena žádná platná položka karty vCard"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Import jednoho nebo více souborů se nezdařil (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Neznámá chyba"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Výběr souboru vCard"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Vyberte soubor vCard, který chcete importovat."</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Čtení karty vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Čtení souborů vCard"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Probíhá import dat karty vCard"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Čtení dat karty vCard se nezdařilo"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Nelze přečíst kartu vCard."\n"Příčina chyby: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> z <xliff:g id="TOTAL_NUMBER">%s</xliff:g> kontaktů"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> z <xliff:g id="TOTAL_NUMBER">%s</xliff:g> souborů"</string>
+ <string name="export_all_contacts" msgid="2873892623335194071">"Všechny kontakty"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Kontakty v místním úložišti"</string>
<string name="export_contact_list" msgid="3165097742175874384">"Export kontaktů"</string>
- <string name="confirm_export_title" msgid="1693047909433122854">"Potvrzení exportu"</string>
- <string name="confirm_export_message" msgid="63482084706768079">"Mají se kontakty exportovat do souboru <xliff:g id="VCARD_FILENAME">%s</xliff:g>?"</string>
- <string name="exporting_contact_failed_title" msgid="1455264422455075858">"Export dat kontaktů se nezdařil"</string>
- <string name="exporting_contact_failed_message" msgid="1426451081541603512">"Export dat kontaktů se nezdařil"\n"Důvod selhání: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
- <string name="fail_reason_too_many_vcard" msgid="5416992255233341607">"Na kartě SD je příliš mnoho dat karty VCard"</string>
- <string name="fail_reason_too_long_filename" msgid="7105223965196949065">"Je požadován příliš dlouhý název souboru (<xliff:g id="FILENAME">%s</xliff:g>)"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Potvrdit export"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Opravdu chcete exportovat seznam kontaktů do souboru <xliff:g id="VCARD_FILENAME">%s</xliff:g>?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Export dat kontaktů se nezdařil"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Export dat kontaktů se nezdařil."\n"Příčina chyby: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Žádný kontakt nelze exportovat"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Na kartě SD je příliš mnoho souborů vCard"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Požadovaný název souboru (<xliff:g id="FILENAME">%s</xliff:g>) je příliš dlouhý"</string>
<string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Cílový adresář <xliff:g id="DIR_NAME">%s</xliff:g> nelze otevřít nebo vytvořit."</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"Export dat kontaktů"</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"Probíhá export dat kontaktů do souboru <xliff:g id="FILE_NAME">%s</xliff:g>"</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Nelze spustit exportní program: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Při exportu došlo k chybě: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Načtení informací z databáze se nezdařilo"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Nelze exportovat žádný kontakt. Pravděpodobně jste zvolili data, která nelze exportovat."</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"Editor karty vCard není správně inicializován"</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Soubor <xliff:g id="FILE_NAME">%s</xliff:g> nelze otevřít: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> z <xliff:g id="TOTAL_NUMBER">%s</xliff:g> kontaktů"</string>
<string name="search_settings_description" msgid="2675223022992445813">"Jména vašich kontaktů"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Přidat 2s pauzu"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Přidat čekání"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Vytočit"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Volat pomocí"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Odeslat zprávu pomocí"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Zapamatovat tuto volbu"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Aplikace potřebná k provedení této akce nebyla nalezena"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Zapamatovat tuto volbu"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Neznámé"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Účty"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importovat nebo exportovat"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importovat nebo exportovat kontakty"</string>
+ <string name="menu_share" msgid="943789700636542260">"Sdílet"</string>
+ <string name="share_via" msgid="563121028023030093">"Sdílet kontakt pomocí"</string>
+ <string name="share_error" msgid="4374508848981697170">"Tento kontakt nelze sdílet."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Jméno"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Přezdívka"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizace"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Webové stránky"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Událost"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"D"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"P"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"O"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Tento kontakt je pouze pro čtení"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Více"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Primární jméno"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Vytvořit kontakt na základě účtu"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Odstranit synchronizovanou skupinu"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Přidat synchronizovanou skupinu"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Další skupiny…"</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Všechny ostatní kontakty"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Všechny kontakty"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Odebráním skupiny <xliff:g id="GROUP">%s</xliff:g> ze synchronizace odeberete ze synchronizace také všechny kontakty mimo skupinu."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Pouze v telefonu (nesynchronizováno)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Zobrazované jméno"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Volat kontakt <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Volat domů"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Volat mobil"</string>
+ <string name="call_work" msgid="5328785911463744028">"Volat do práce"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Volat pracovní fax"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Volat domácí fax"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Volat pager"</string>
+ <string name="call_other" msgid="5605584621798108205">"Volat ostatní"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Volat na číslo zpětného volání"</string>
+ <string name="call_car" msgid="3280537320306436445">"Volat do auta"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Volat firmu (hlavní)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Volat na číslo ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Volat na hlavní číslo"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Volat jiné číslo faxu"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Volat radiostanici"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Volat na číslo Telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Volat na číslo TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Volat na pracovní mobil"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Volat na pracovní pager"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Volat na číslo <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Volat MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Poslat SMS na <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"SMS domů"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"SMS na mobil"</string>
+ <string name="sms_work" msgid="2269624156655267740">"SMS do práce"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"SMS na pracovní fax"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"SMS na domácí fax"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"SMS na pager"</string>
+ <string name="sms_other" msgid="5131921487474531617">"SMS – ostatní"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Odeslat zprávu na číslo zpětného volání"</string>
+ <string name="sms_car" msgid="7444227058437359641">"SMS do auta"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"SMS do firmy (hlavní)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Odeslat zprávu na číslo ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Odeslat zprávu na hlavní číslo"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Odeslat zprávu na jiné číslo faxu"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"SMS na radiotelefon"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Odeslat zprávu na číslo Telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Odeslat zprávu na číslo TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Odeslat zprávu na pracovní mobil"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Odeslat zprávu na pracovní pager"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Odeslat zprávu asistentovi <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"SMS na číslo MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"E-mail domů"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-mail na mobil"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-mail do práce"</string>
+ <string name="email_other" msgid="8093933498541795832">"E-mail ostatní"</string>
+ <string name="email_custom" msgid="7548003991586214105">"E-mail <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-mail"</string>
+ <string name="map_home" msgid="1243547733423343982">"Zobrazit adresu domů"</string>
+ <string name="map_work" msgid="1360474076921878088">"Zobrazit pracovní adresu"</string>
+ <string name="map_other" msgid="5560707927535653892">"Zobrazit ostatní adresy"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Zobrazit adresu <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chatovat pomocí AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chatovat pomocí Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chatovat pomocí Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chatovat pomocí Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chatovat pomocí QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chatovat pomocí Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chatovat pomocí ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chatovat pomocí Jabberu"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Ulice"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Číslo poštovní schránky"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Čtvrť"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Město"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Stát"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"PSČ"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Země"</string>
+ <string name="name_given" msgid="1687286314106019813">"Křestní jméno"</string>
+ <string name="name_family" msgid="3416695586119999058">"Příjmení"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Titul před jménem"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Další jméno"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Titul za jménem"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Křestní jméno (foneticky)"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Druhé jméno (foneticky)"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Příjmení (foneticky)"</string>
+ <string name="split_label" msgid="8262112659919449087">"Rozdělit"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Vytvořit z těchto dat nový kontakt."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Z účtu služby <xliff:g id="SOURCE">%1$s</xliff:g>: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"Kontakt ze zdroje <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="from_account_format" msgid="687567483928582084">"z účtu <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Použít tuto fotografii"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"Kontaktní informace ze zdroje <xliff:g id="SOURCE">%1$s</xliff:g> není možné na tomto zařízení upravit."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"U tohoto kontaktu nejsou uvedeny dodatečné informace"</string>
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 209b738..dc4e61b 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -16,18 +16,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Kontakter"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Opkald"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefon"</string>
<string name="shortcutContact" msgid="749243779392912958">"Kontakt"</string>
- <!-- no translation found for shortcutDialContact (7165340343023469996) -->
- <skip />
- <!-- no translation found for shortcutMessageContact (3025782962770298900) -->
- <skip />
- <!-- no translation found for shortcutActivityTitle (6642877210643565436) -->
- <skip />
- <!-- no translation found for callShortcutActivityTitle (6065749861423648991) -->
- <skip />
- <!-- no translation found for messageShortcutActivityTitle (3084542316620335911) -->
- <skip />
+ <string name="shortcutDialContact" msgid="746622101599186779">"Direkte opkald"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Direkte besked"</string>
+ <string name="shortcutActivityTitle" msgid="6642877210643565436">"Vælg en kontaktgenvej"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"Vælg et nummer at ringe til"</string>
+ <string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Vælg et nummer at sende besked til"</string>
<string name="starredList" msgid="4817256136413959463">"Stjernemarkerede"</string>
<string name="frequentList" msgid="7154768136473953056">"Ofte"</string>
<string name="strequentList" msgid="5640192862059373511">"Favorit"</string>
@@ -45,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Vis stregkode"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Rediger kontakt"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Slet kontakt"</string>
- <string name="menu_call" msgid="7359207953236681606">"Opkald"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Send SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Ring til kontaktperson"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Send sms til kontaktperson"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Send e-mail"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Kortadresse"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Gør til standardnummer"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Benyt e-mail som standard"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Opdel"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Opdel kontakt"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Kontaktpersonerne blev opdelt"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Opdel kontaktperson"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Er du sikker på, at du vil opdele denne ene kontaktperson i flere kontaktpersoner: én for hver sæt af de indeholdte kontaktoplysninger?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Føj til"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Vis kilder"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Skjul kilder"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Føj til kontakt"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Føj til kontaktpersoner"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Vælg den kontaktperson, du ønsker at forbinde til <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Vis alle kontaktpersoner"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Foreslåede kontaktpersoner"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Alle kontakter"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Tilføjede kontaktpersoner"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Valgmuligheder"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Valgmuligheder"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Slet"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Du kan ikke slette kontaktpersoner på skrivebeskyttede konti, men du kan skjule dem i dine lister over kontaktpersoner."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Denne kontaktperson indeholder oplysninger fra flere konti. Oplysningerne fra skrivebeskyttede konti vil blive skjult i dine lister over kontaktpersoner, ikke slettet."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Sletning af denne kontaktperson sletter oplysninger fra flere konti."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Denne kontakt slettes"</string>
<string name="menu_done" msgid="796017761764190697">"Færdig"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Vend tilbage"</string>
@@ -60,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonetisk"</string>
<string name="label_notes" msgid="8337354953278341042">"Noter"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Ringetone"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Grupper"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Rediger grupper"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Fornavn og efternavn"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Fonetisk navn"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Virksomhed"</string>
@@ -69,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Telefonnummer"</string>
<string name="ghostData_email" msgid="6184537075551565919">"E-mail-adresse"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Postadresse"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Vis grupper"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Kontakten eksisterer ikke."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Opret ny kontakt"</string>
<string name="selectLabel" msgid="4255424123394910733">"Vælg etiket"</string>
@@ -85,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Der er ingen tilgængelige billeder på telefonen."</string>
<string name="attachToContact" msgid="8820530304406066714">"Kontaktikon"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Navn på tilpasset etiket"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Vis grupper"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Visningsindstillinger"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Visningsindstillinger"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Rediger grupper, synk."</string>
<string name="importFromSim" msgid="8383900146531125319">"Importer kontakter"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Send opkald direkte til voicemail"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Opkald sendes direkte til voicemail."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Standard"</string>
<string name="addPicture" msgid="1594679312161537678">"Tilføj ikon"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Skift ikon"</string>
<string name="removePicture" msgid="3041230993155966350">"Fjern ikon"</string>
<string name="noContacts" msgid="8579310973261953559">"Der er ingen kontakter."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Der blev ikke fundet nogen matchende kontaktpersoner."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Der er ingen kontakter med telefonnumre."</string>
<string name="noFavorites" msgid="812766386743315815">"Der er ingen favoritter."</string>
<string name="select_group_title" msgid="7955698611959835612">"Grupper"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Din gruppe \"<xliff:g id="GROUPNAME">%s</xliff:g>\" er tom."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Alle kontakter"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Kun kontaktpersoner med telefoner"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Vis kun kontaktpersoner med telefonnumre"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Vælg de kontaktpersoner, der skal vises"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> kontakter"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> kontaktpersoner, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> med telefoner"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Synkroniser alle kontakter"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Mine kontakter"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Mine kontaktpersoner"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Kontakter med telefonnumre"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Stjernemarkerede i Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Gemmer kontaktperson ..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Gemmer visningsindstillinger ..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Kontakt oprettet."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Kontakten er gemt."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Fejl, kunne ikke gemme ændringer af kontaktpersoner"</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Ring til nummer"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Telefonnumre"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Send SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Send sms"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Send e-mail"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"E-mail-adresser"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Send chatbesked"</string>
@@ -115,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Kortadresse"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Postadresse"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organisationer"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Grupper"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Andre oplysninger"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Andre valgmuligheder"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Flere"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Viser 1 kontaktperson med telefonnummer"</item>
+ <item quantity="other" msgid="6133262880804110289">"Viser <xliff:g id="COUNT">%d</xliff:g> kontaktpersoner med telefonnumre"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Der er ingen synlige kontaktpersoner med telefonnumre"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Viser 1 kontaktperson"</item>
+ <item quantity="other" msgid="2865867557378939630">"Viser <xliff:g id="COUNT">%d</xliff:g> kontaktpersoner"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Ingen synlige kontaktpersoner"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"Fandt 1 kontaktperson"</item>
+ <item quantity="other" msgid="7752927996850263152">"Fandt <xliff:g id="COUNT">%d</xliff:g> kontaktpersoner"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Kontaktpersonen blev ikke fundet"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Sociale"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakter"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favorit"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Opkald"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Opk.liste"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Alle kontakter"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Stjernemarkerede kontakter"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Kontakter med telefonnumre"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Send SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Send sms"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Ring til <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Rediger nummer inden opkald"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Føj til kontakter"</string>
@@ -133,19 +185,23 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Ryd opkaldsliste"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Opkaldsliste er tom."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Voicemail"</string>
<string name="unknown" msgid="740067747858270469">"Ukendte"</string>
<string name="private_num" msgid="6374339738119166953">"Privat nummer"</string>
<string name="payphone" msgid="4864313342828942922">"Betalingstelefon"</string>
<string name="dialerKeyboardHintText" msgid="5401660096579787344">"Brug tastatur til at ringe op"</string>
- <string name="dialerDialpadHintText" msgid="5824490365898349041">"Ring for at tilføje et opkald"</string>
+ <string name="dialerDialpadHintText" msgid="5824490365898349041">"Ring og tilføj et opkald"</string>
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Indlæser fra SIM-kort ..."</string>
<string name="simContacts_title" msgid="27341688347689769">"Kontakter på SIM-kort"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Synkroniser dine Google-kontakter!"</font>\n"Når du har synkroniseret din telefon, bliver dine kontakter tilgængelige, uanset hvor du befinder dig."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Du har ingen kontakter."\n\n"For at tilføje kontakter skal du trykke på "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" og vælge:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for at oprette en ny kontakt fra bunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer kontakter"</b></font>" for at tilføje kontakter fra dit SIM-kort"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Du har ingen kontakter."\n\n"For at tilføje kontakter skal du trykke på "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" og vælge:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Rediger grupper, der skal synkroniseres"</b></font>", for at tilføje fra en ny eller eksisterende Google-konto"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for at oprette en ny kontakt fra bunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer kontakter"</b></font>" for at tilføje kontakter fra dit SIM-kort"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Du har ingen kontaktpersoner, der kan vises."\n\n"Hvis du vil tilføje kontaktpersoner, skal du trykke på "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" og på"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konti"</b></font>" for at tilføje eller konfigurere en konto med kontaktpersoner, som du kan synkronisere med telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontaktperson"</b></font>" for at oprette en ny kontaktperson helt fra bunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/eksporter"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Du har ingen kontaktpersoner, der kan vises. (Hvis du lige har tilføjet en konto, kan det tage et par minutter at synkronisere kontaktpersoner)."\n\n"Hvis du vil tilføje kontaktpersoner, skal du trykke på "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" og på"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konti"</b></font>" for at tilføje eller konfigurere en konto med kontaktpersoner, du kan synkronisere til telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsindstillinger"</b></font>" for at ændre, hvilke kontaktpersoner der er synlige"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontaktperson"</b></font>" for at oprette en ny kontaktperson fra bunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/eksporter"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Du har ingen kontaktpersoner, der kan vises."\n\n"Hvis du vil tilføje kontaktpersoner, skal du trykke på "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" og på"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konti"</b></font>" for at tilføje eller konfigurere en konto med kontaktpersoner, du kan synkronisere med telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontaktperson"</b></font>" for at oprette en ny kontaktperson fra bunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/eksporter"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Du har ingen kontaktpersoner, der kan vises. (Hvis du lige har tilføjet en konto, kan det tage et par minutter at synkronisere kontaktpersonerne)."\n\n"Hvis du vil tilføje kontaktpersoner, skal du trykke på "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" og på"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konti"</b></font>" for at tilføje eller konfigurere en konto med kontaktpersoner, du kan synkronisere til telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsindstillinger"</b></font>" for at ændre, hvilke kontaktpersoner der er synlige"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontaktperson"</b></font>" for at oprette en ny kontaktperson fra bunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/eksporter"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Du har ingen favoritter."\n\n"Sådan føjer du en kontaktperson til din liste over favoritter:"\n\n" "<li>"Tryk på fanen "<b>"Kontaktpersoner"</b>\n</li>" "\n<li>"Tryk på den kontaktperson, du ønsker at føje til dine foretrukne"\n</li>" "\n<li>"Tryk på stjerne ud for kontaktpersonens navn"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Vælg grupper, der skal synkroniseres"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Alle kontakter"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Alle kontakter"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Stjernemarkerede"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Telefoner"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Brug touch-tone-tastatur"</string>
@@ -176,84 +232,191 @@
<string name="returnCall" msgid="8171961914203617813">"Returner opkald"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> min. <xliff:g id="SECONDS">%s</xliff:g> sek."</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Ofte ringet til"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Tilføj kontakt"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Tilføj kontakt"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Føj \"<xliff:g id="EMAIL">%s</xliff:g>\" til kontakter?"</string>
- <!-- no translation found for description_image_button_one (1740638037139856139) -->
- <skip />
- <!-- no translation found for description_image_button_two (5882638439003731308) -->
- <skip />
- <!-- no translation found for description_image_button_three (8709731759376015180) -->
- <skip />
- <!-- no translation found for description_image_button_four (3530239685642246130) -->
- <skip />
- <!-- no translation found for description_image_button_five (1182465427501188413) -->
- <skip />
- <!-- no translation found for description_image_button_six (2093656269261415475) -->
- <skip />
- <!-- no translation found for description_image_button_seven (2450357020447676481) -->
- <skip />
- <!-- no translation found for description_image_button_eight (6969435115163287801) -->
- <skip />
- <!-- no translation found for description_image_button_nine (7857248695662558323) -->
- <skip />
- <!-- no translation found for description_image_button_star (3365919907520767866) -->
- <skip />
- <!-- no translation found for description_image_button_zero (4133108949401820710) -->
- <skip />
- <!-- no translation found for description_image_button_pound (3039765597595889230) -->
- <skip />
- <string name="no_sdcard_title" msgid="6455416795090113715">"Der er ikke noget SD-kort"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Der blev ikke fundet noget SD-kort"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Søger efter VCard"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Alle"</string>
+ <string name="description_image_button_one" msgid="1740638037139856139">"et"</string>
+ <string name="description_image_button_two" msgid="5882638439003731308">"to"</string>
+ <string name="description_image_button_three" msgid="8709731759376015180">"tre"</string>
+ <string name="description_image_button_four" msgid="3530239685642246130">"fire"</string>
+ <string name="description_image_button_five" msgid="1182465427501188413">"fem"</string>
+ <string name="description_image_button_six" msgid="2093656269261415475">"seks"</string>
+ <string name="description_image_button_seven" msgid="2450357020447676481">"syv"</string>
+ <string name="description_image_button_eight" msgid="6969435115163287801">"otte"</string>
+ <string name="description_image_button_nine" msgid="7857248695662558323">"ni"</string>
+ <string name="description_image_button_star" msgid="3365919907520767866">"stjernemarker"</string>
+ <string name="description_image_button_zero" msgid="4133108949401820710">"nul"</string>
+ <string name="description_image_button_pound" msgid="3039765597595889230">"pund"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Der er intet SD-kort"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Der blev ikke fundet noget SD-kort"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Søger efter vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Hvor ønsker du at importere kontakter fra?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIM-kort"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"SD-kort"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importer alle VCard-filer"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Importer en VCard-fil"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Søger efter VCard-data på VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Scanningen af SD-kortet mislykkedes"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Scanningen af SD-kortet mislykkedes"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importer fra SIM-kort"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importer fra SD-kort"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Eksporter til SD-kort"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importer en VCard-fil"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importer flere VCard-filer"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importer alle VCard-filer"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Søger efter vCard-kort på SD-kortet"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Scanningen af SD-kortet mislykkedes"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Scanningen af SD-kortet mislykkedes: (Årsag: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O-fejl"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"VCard kunne ikke parses"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Der blev ikke fundet noget VCard på SD-kortet"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Der blev ikke fundet nogen gyldig VCard-post til dit udvalg"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Vælg VCard-fil"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Vælg en VCard-fil, der skal importeres"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Læser VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Læser VCard-fil(er)"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Importerer VCard-data"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Læsning af VCard-data mislykkedes"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"VCard-data kunne ikke læses"\n"Årsag til fejl: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"vCard kunne ikke parses pga. en uventet årsag"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"vCard kunne ikke parses, selv om det ser ud til at være et gyldigt format, da den nuværende implementering ikke understøtter det"</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Der blev ikke fundet nogen VCard-fil på SD-kortet"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Der blev ikke fundet nogen gyldig vCard-post for dit valg"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"En eller flere filer blev ikke importeret (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Ukendt fejl"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Vælg vCard-fil"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Vælg en vCard-fil, der skal importeres"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Læser vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Læser vCard-fil(er)"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Importerer vCard-data"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Læsning af vCard-data mislykkedes"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"vCard kunne ikke læses."\n"Årsag til fejl: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> af <xliff:g id="TOTAL_NUMBER">%s</xliff:g> kontakter"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> af <xliff:g id="TOTAL_NUMBER">%s</xliff:g> filer"</string>
- <!-- no translation found for export_contact_list (3165097742175874384) -->
- <skip />
- <!-- no translation found for confirm_export_title (1693047909433122854) -->
- <skip />
- <!-- no translation found for confirm_export_message (63482084706768079) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_title (1455264422455075858) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_message (1426451081541603512) -->
- <skip />
- <!-- no translation found for fail_reason_too_many_vcard (5416992255233341607) -->
- <skip />
- <!-- no translation found for fail_reason_too_long_filename (7105223965196949065) -->
- <skip />
- <!-- no translation found for fail_reason_cannot_open_destination_dir (1739293936432987758) -->
- <skip />
- <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
- <skip />
- <!-- no translation found for exporting_contact_list_message (5640326540405486055) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_initialize_exporter (4943708332700987376) -->
- <skip />
- <!-- no translation found for fail_reason_error_occurred_during_export (2151165129433831202) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_open_file (4013520943128739511) -->
- <skip />
- <!-- no translation found for exporting_contact_list_progress (560522409559101193) -->
- <skip />
- <!-- no translation found for search_settings_description (2675223022992445813) -->
- <skip />
+ <string name="export_all_contacts" msgid="2873892623335194071">"Alle kontakter"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Kontaktpersoner, som er lagret lokalt"</string>
+ <string name="export_contact_list" msgid="3165097742175874384">"Eksporter kontakter"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Bekræft eksport"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Er du sikker på, at du vil eksportere listen over kontaktpersoner til \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\"?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Eksport af kontaktpersondata mislykkedes"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Eksport af kontaktpersondata mislykkedes."\n"Årsag til fejl: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Der er ingen kontaktpersoner, der kan eksporteres"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Der er for mange vCard-data på SD-kortet"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Det krævede filnavn er for langt (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Destinationsmappen \"<xliff:g id="DIR_NAME">%s</xliff:g>\" kan ikke åbnes eller oprettes"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Eksporterer kontaktdata"</string>
+ <string name="exporting_contact_list_message" msgid="5640326540405486055">"Kontaktdata eksporteres til \"<xliff:g id="FILE_NAME">%s</xliff:g>\""</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Eksportfunktionen kunne ikke startes: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Der opstod en fejl under eksport: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Kunne ikke hente databaseoplysninger"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Der er ingen kontaktpersoner, som kan eksporteres. Du har måske valgt data, som ikke kan eksporteres"</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"vCard-oprettelse ikke korrekt initialiseret"</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" kunne ikke åbnes: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> af <xliff:g id="TOTAL_NUMBER">%s</xliff:g> kontakter"</string>
+ <string name="search_settings_description" msgid="2675223022992445813">"Navne på dine kontakter"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Tilføj pause på 2 sek."</string>
+ <string name="add_wait" msgid="3360818652790319634">"Tilføj Vent"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Ring til"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Ring ved hjælp af"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Send sms ved hjælp af"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Husk dette valg"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Der blev ikke fundet noget program til denne handling"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Husk dette valg"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Ukendte"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Konti"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Import/eksport af"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importer/eksporter kontaktpersoner"</string>
+ <string name="menu_share" msgid="943789700636542260">"Del"</string>
+ <string name="share_via" msgid="563121028023030093">"Del kontaktperson via"</string>
+ <string name="share_error" msgid="4374508848981697170">"Denne kontaktperson kan ikke deles."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Navn"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Kaldenavn"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Websted"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Begivenhed"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"H"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"O"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"O"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Denne kontaktperson er skrivebeskyttet"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Flere"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Primærnavn"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Opret kontaktperson under konto"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Fjern synkroniseringsgruppe"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Tilføj synkroniseringsgruppe"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Flere grupper ..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Alle andre kontaktpersoner"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Alle kontakter"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Hvis \'<xliff:g id="GROUP">%s</xliff:g>\' fjernes fra synkronisering, vil kontaktpersoner, der ikke er i grupper, også fjernes fra synkroniseringen."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Kun telefon (ikke synkroniseret)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Visningsnavn"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Ring til <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Ring hjem"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Ring til mobil"</string>
+ <string name="call_work" msgid="5328785911463744028">"Ring til arbejde"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Ring til arbejdsfax"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Ring til hjemmefax"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Ring til personsøger"</string>
+ <string name="call_other" msgid="5605584621798108205">"Ring til øvrige"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Ring til tilbagekald"</string>
+ <string name="call_car" msgid="3280537320306436445">"Ring til bil"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Ring til arbejde (hovednummer)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Ring til ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Ring til hoved"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Ring til anden fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Ring til radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Ring til telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Ring til TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Ring til arbejdsmobiltelefon"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Ring til personsøger til arbejdet"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Ring til <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Ring til MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Tekst <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Sms til hjem"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Sms til mobil"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Sms til arbejde"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Sms til arbejdsfax"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Sms til hjemmefax"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Sms til personsøger"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Sms til anden"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Send sms til mistede opkald"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Sms til bil"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Sms til arbejde (hovednummer)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Send sms til ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Send sms til hoved"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Send sms til anden fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Sms til radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Send sms til telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Send sms til TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Send sms til arbejdsmobiltelefon"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Send sms til personsøger til arbejdet"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Send sms til <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Sms til MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"E-mail til hjem"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-mail til mobil"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-mail til arbejde"</string>
+ <string name="email_other" msgid="8093933498541795832">"E-mail til anden"</string>
+ <string name="email_custom" msgid="7548003991586214105">"E-mail <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-mail"</string>
+ <string name="map_home" msgid="1243547733423343982">"Vis hjemmeadresse"</string>
+ <string name="map_work" msgid="1360474076921878088">"Vis arbejdsadresse"</string>
+ <string name="map_other" msgid="5560707927535653892">"Vis anden adresse"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Vis <xliff:g id="CUSTOM">%s</xliff:g> adresse"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chat ved hjælp af AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chat ved hjælp af Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chat ved hjælp af Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chat ved hjælp af Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chat ved hjælp af QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chat ved hjælp af Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chat ved hjælp af ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chat ved hjælp af Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"chat"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Gade"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Postboks"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Nabolag"</string>
+ <string name="postal_city" msgid="6597491300084895548">"By"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Tilstand"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postnummer"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Land"</string>
+ <string name="name_given" msgid="1687286314106019813">"Fornavn"</string>
+ <string name="name_family" msgid="3416695586119999058">"Efternavn"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Navnepræfiks"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Mellemnavn"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Navnesuffiks"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Fonetisk fornavn"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetisk mellemnavn"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Fonetisk efternavn"</string>
+ <string name="split_label" msgid="8262112659919449087">"Opdel"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Gør disse data til selvstændig kontaktperson"</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Fra <xliff:g id="SOURCE">%1$s</xliff:g>-konto: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> kontaktperson"</string>
+ <string name="from_account_format" msgid="687567483928582084">"fra<xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Brug dette billede"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> kontaktoplysninger kan ikke redigeres på denne enhed."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Ingen yderligere oplysninger for denne kontaktperson"</string>
</resources>
diff --git a/res/values-de/config.xml b/res/values-de/config.xml
deleted file mode 100644
index 07b3c7e..0000000
--- a/res/values-de/config.xml
+++ /dev/null
@@ -1,28 +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">
- <!-- no translation found for config_export_vcard_type (9145748078116159716) -->
- <skip />
- <string name="config_export_dir" msgid="222182743639478636">"/sdcard"</string>
- <!-- no translation found for config_export_file_prefix (3022868431158658122) -->
- <skip />
- <!-- no translation found for config_export_file_suffix (16505844221142195) -->
- <skip />
- <string name="config_export_file_extension" msgid="1758878818611339161">"vcf"</string>
- <!-- no translation found for config_export_extensions_to_consider (5095044502091950623) -->
- <skip />
-</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 0d7520c..b22b883 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Kontakte"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Telefon"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefon"</string>
<string name="shortcutContact" msgid="749243779392912958">"Kontakt"</string>
- <string name="shortcutDialContact" msgid="7165340343023469996">"Direktwahl"</string>
- <string name="shortcutMessageContact" msgid="3025782962770298900">"Direktnachricht"</string>
+ <string name="shortcutDialContact" msgid="746622101599186779">"Direktwahl"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Direktnachricht"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"Verknüpfung für Kontakt auswählen"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"Nummer für den Anruf auswählen"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Nummer für Nachricht auswählen"</string>
@@ -40,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Barcode anzeigen"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Kontakt bearbeiten"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Kontakt löschen"</string>
- <string name="menu_call" msgid="7359207953236681606">"Anruf"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"SMS/MMS senden"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Kontakt anrufen"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Textnachricht an Kontakt"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"E-Mail senden"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Adresse auf der Karte"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Als Standardnummer festlegen"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Standard-E-Mail festlegen"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Unterteilen"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Kontakt teilen"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Kontakte unterteilt"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Kontakt unterteilen"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Sind Sie sicher, dass Sie diesen Kontakt in mehrere Kontakte unterteilen möchten, einen für jedes darin enthaltene Kontaktdetail?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Anfügen"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Quellen anzeigen"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Quellen ausblenden"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Kontakt verknüpfen"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Kontakte anfügen"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Wählen Sie den Kontakt aus, den Sie mit <xliff:g id="NAME">%s</xliff:g> verknüpfen möchten."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Alle Kontakte anzeigen"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Vorgeschlagene Kontakte"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Alle Kontakte"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Kontakte wurden verknüpft."</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Optionen"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Optionen"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Löschen"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Sie können keine Kontakte aus schreibgeschützten Konten löschen. Sie können sie jedoch in Ihren Kontaktlisten ausblenden."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Dieser Kontakt enthält Informationen aus mehreren Konten. Informationen aus schreibgeschützten Konten werden nicht gelöscht, sondern in Ihren Kontaktlisten ausgeblendet."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Wenn Sie diesen Kontakt löschen, werden Informationen aus mehreren Konten gelöscht."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Dieser Kontakt wird gelöscht."</string>
<string name="menu_done" msgid="796017761764190697">"Fertig"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Rückgängig"</string>
@@ -55,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Phonetisch"</string>
<string name="label_notes" msgid="8337354953278341042">"Notizen"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Klingelton"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Gruppen"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Gruppen bearbeiten"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Vor- und Nachname"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Phonetischer Name"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Unternehmen"</string>
@@ -64,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Telefonnummer"</string>
<string name="ghostData_email" msgid="6184537075551565919">"E-Mail-Adresse"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Postanschrift"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Gruppe anzeigen"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Dieser Kontakt existiert nicht."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Neuen Kontakt erstellen"</string>
<string name="selectLabel" msgid="4255424123394910733">"Wählen Sie ein Label aus."</string>
@@ -80,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Auf dem Telefon sind keine Bilder verfügbar."</string>
<string name="attachToContact" msgid="8820530304406066714">"Kontaktsymbol"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Name des benutzerdef. Labels"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Gruppe anzeigen"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Anzeigeoptionen"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Anzeigeoptionen"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Sync-Gruppen bearb."</string>
<string name="importFromSim" msgid="8383900146531125319">"Kontakte importieren"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Anrufe direkt an Mailbox senden"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Anrufe werden direkt an Mailbox gesendet"</string>
<string name="default_ringtone" msgid="9099988849649827972">"Standard"</string>
<string name="addPicture" msgid="1594679312161537678">"Symbol hinzufügen"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Symbol ändern"</string>
<string name="removePicture" msgid="3041230993155966350">"Symbol entfernen"</string>
<string name="noContacts" msgid="8579310973261953559">"Keine Kontakte"</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Keine passenden Kontakte gefunden"</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Keine Kontakte mit Telefonnummern"</string>
<string name="noFavorites" msgid="812766386743315815">"Keine Favoriten"</string>
<string name="select_group_title" msgid="7955698611959835612">"Gruppen"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Ihre Gruppe \"<xliff:g id="GROUPNAME">%s</xliff:g>\" ist leer."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Alle Kontakte"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Nur Kontakte mit Telefonen"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Nur Kontakte mit Telefonnummern anzeigen"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Kontakte zum Anzeigen auswählen"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> Kontakte"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> Kontakte, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> mit Telefon"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Alle Kontakte synchronisieren"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Meine Kontakte"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Meine Kontakte"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Kontakte mit Telefonnummern"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"In Android markiert"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Kontakt wird gespeichert..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Anzeigeoptionen werden gespeichert..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Kontakt erstellt"</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Kontakt gespeichert"</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Fehler, Kontaktänderungen konnten nicht gespeichert werden."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Rufnummer"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Telefonnummern"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"SMS/MMS senden"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Textnachricht senden"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"E-Mail senden"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"E-Mail-Adressen"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Per Chat kontaktieren"</string>
@@ -110,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Adresse in Maps"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Postanschrift"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organisationen"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Gruppen"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Mehr Informationen"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Sonstige Optionen"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Mehr"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"1 Kontakt mit Telefonnummer wird angezeigt."</item>
+ <item quantity="other" msgid="6133262880804110289">"Zeigt <xliff:g id="COUNT">%d</xliff:g> Kontakte mit Telefonnummern an"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Keine sichtbaren Kontakte mit Telefonnummern"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"1 Kontakt wird angezeigt."</item>
+ <item quantity="other" msgid="2865867557378939630">"<xliff:g id="COUNT">%d</xliff:g> Kontakte werden angezeigt."</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Keine sichtbaren Kontakte"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"1 Kontakt gefunden"</item>
+ <item quantity="other" msgid="7752927996850263152">"<xliff:g id="COUNT">%d</xliff:g> Kontakte gefunden"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Kein Kontakt gefunden"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Sozial"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakte"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriten"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Telefon"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Anrufe"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Alle Kontakte"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Markierte Kontakte"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Kontakte mit Telefonnummern"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"SMS-Nachricht senden"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Textnachricht senden"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"<xliff:g id="NAME">%s</xliff:g> anrufen"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Nummer vor Anruf bearbeiten"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Zu Kontakten hinzufügen"</string>
@@ -128,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Anrufliste löschen"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Anrufliste ist leer"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Mailbox"</string>
<string name="unknown" msgid="740067747858270469">"Unbekannt"</string>
<string name="private_num" msgid="6374339738119166953">"Private Nummer"</string>
@@ -137,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Ladevorgang von SIM-Karte läuft..."</string>
<string name="simContacts_title" msgid="27341688347689769">"Kontakte auf SIM-Karte"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Synchronisieren Sie Ihre Google-Kontakte!"</font>" "\n"Nach der Synchronisierung stehen Ihnen Ihre Kontakte überall zur Verfügung."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Es sind keine Kontakte vorhanden."\n\n"Drücken Sie zum Hinzufügen von Kontakten die "<font fgcolor="#ffffffff"><b>"Menütaste"</b></font>" und wählen Sie Folgendes aus:"\n\n" "<li><font fgcolor="#ffffffff"><b></b>"Neuer Kontakt"</font>\n", um einen neuen Kontakt zu erstellen"</li>\n<li>" "<font fgcolor="#ffffffff"><b></b></font>"Kontakte importieren"\n</li>", um Kontakte von Ihrer SIM-Karte hinzuzufügen"</string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Sie haben keine Kontakte."\n\n"Drücken Sie zum Hinzufügen die "<font fgcolor="#ffffffff"><b>"Menütaste"</b></font>" und wählen Sie"\n\n<li><font fgcolor="#ffffffff"><b>"Synchronisierungsgruppen bearbeiten"</b></font>", um Kontakte mit einem neuen oder bestehenden Google-Konto zu synchronisieren,"\n</li>\n<li><font fgcolor="#ffffffff"><b>"Neuer Kontakt"</b></font>", um einen Kontakt neu zu erstellen, "\n</li>\n<li><font fgcolor="#ffffffff"><b>"Kontakte importieren"</b></font>", um Kontakte von Ihrer SIM-Karte hinzuzufügen."\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Es können keine Kontakte angezeigt werden."\n\n"Tippen Sie zum Hinzufügen von Kontakten auf "<font fgcolor="#ffffffff"><b>"Menü"</b></font>" und tippen Sie anschließend auf "\n" "\n<li><font fgcolor="#ffffffff"><b>"Konten"</b></font>", um ein Konto hinzuzufügen oder mit Kontakten zu konfigurieren, die mit dem Telefon synchronisiert werden können."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Neuer Kontakt"</b></font>", um einen neuen Kontakt von Grund auf zu erstellen."\n</li>\n<li><font fgcolor="#ffffffff"><b>"Import/Export"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Es können keine Kontakte angezeigt werden. Wenn Sie gerade ein Konto hinzugefügt haben, kann es einige Minuten dauern, bis die Kontakte synchronisiert sind."\n\n"Drücken Sie zum Hinzufügen von Kontakten auf "<font fgcolor="#ffffffff"><b>"Menü"</b></font>" und tippen Sie anschließend auf "\n" "\n<li><font fgcolor="#ffffffff"><b>"Konten"</b></font>", um ein Konto hinzuzufügen oder mit Kontakten zu konfigurieren, die mit dem Telefon synchronisiert werden können."\n" "</li>\n<li><font fgcolor="#ffffffff"><b>"Anzeigeoptionen"</b></font>", um zu ändern, welche Kontakte angezeigt werden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Neuer Kontakt"</b></font>", um einen neuen Kontakt von Grund auf zu erstellen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Import/Export"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Es können keine Kontakte angezeigt werden."\n\n"Tippen Sie zum Hinzufügen von Kontakten auf "<font fgcolor="#ffffffff"><b>"Menü"</b></font>" und tippen Sie anschließend auf "\n" "\n<li><font fgcolor="#ffffffff"><b>"Konten"</b></font>", um ein Konto hinzuzufügen oder mit Kontakten zu konfigurieren, die mit dem Telefon synchronisiert werden können."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Neuer Kontakt"</b></font>", um einen neuen Kontakt von Grund auf zu erstellen"\n</li>\n<li><font fgcolor="#ffffffff"><b>"Import/Export"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Es können keine Kontakte angezeigt werden. Wenn Sie gerade ein Konto hinzugefügt haben, kann es einige Minuten dauern, bis die Kontakte synchronisiert sind."\n\n"Tippen Sie zum Hinzufügen von Kontakten auf "<font fgcolor="#ffffffff"><b>"Menü"</b></font>" und tippen Sie anschließend auf "\n" "\n<li><font fgcolor="#ffffffff"><b>"Konten"</b></font>", um ein Konto hinzuzufügen oder mit Kontakten zu konfigurieren, die mit dem Telefon synchronisiert werden können."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Anzeigeoptionen"</b></font>", um zu ändern, welche Kontakte angezeigt werden"\n</li>\n<li><font fgcolor="#ffffffff"><b>"Neuer Kontakt"</b></font>", um einen neuen Kontakt von Grund auf zu erstellen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Import/Export"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Sie haben keine Favoriten."\n\n"So fügen Sie einen Kontakt zu Ihrer Favoritenliste hinzu:"\n\n" "<li>"Tippen Sie auf die Registerkarte "<b>"Kontakte"</b>"."\n</li>" "\n<li>"Tippen Sie auf den Kontakt, den Sie zu Ihren Favoriten hinzufügen möchten."\n</li>" "\n<li>"Tippen Sie auf die Markierung neben dem Kontaktnamen."\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Zu synchronisierende Gruppen auswählen"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Alle Kontakte"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Alle Kontakte"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Markiert"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Nummern"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Telefontastatur verwenden"</string>
@@ -171,8 +232,9 @@
<string name="returnCall" msgid="8171961914203617813">"Zurückrufen"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> Minuten, <xliff:g id="SECONDS">%s</xliff:g> Sekunden"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Häufig angerufen"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Kontakt hinzufügen"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Kontakt hinzufügen"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"\"<xliff:g id="EMAIL">%s</xliff:g>\" zu den Kontakten hinzufügen?"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Alle"</string>
<string name="description_image_button_one" msgid="1740638037139856139">"eins"</string>
<string name="description_image_button_two" msgid="5882638439003731308">"zwei"</string>
<string name="description_image_button_three" msgid="8709731759376015180">"drei"</string>
@@ -185,43 +247,176 @@
<string name="description_image_button_star" msgid="3365919907520767866">"Markierung"</string>
<string name="description_image_button_zero" msgid="4133108949401820710">"null"</string>
<string name="description_image_button_pound" msgid="3039765597595889230">"Pfund"</string>
- <string name="no_sdcard_title" msgid="6455416795090113715">"Keine SD-Karte"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Keine SD-Karte gefunden"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"VCard wird gesucht."</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Keine SD-Karte"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Keine SD-Karte gefunden"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"vCard wird gesucht."</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Aus welcher Quelle möchten Sie Kontakte importieren?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIM-Karte"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"SD-Karte"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Alle VCard-Dateien importieren"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Eine VCard-Datei importieren"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"VCard-Daten werden auf VCard gesucht."</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Fehler beim Lesen der SD-Karte"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Fehler beim Lesen der SD-Karte"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Von SIM-Karte importieren"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Von SD-Karte importieren"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"An SD-Karte exportieren"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Eine VCard-Datei importieren"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Mehrere VCard-Dateien importieren"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Alle VCard-Dateien importieren"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Suche nach einer vCard-Information auf der SD-Karte"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Fehler beim Lesen der SD-Karte"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Fehler beim Lesen der SD-Karte. Grund: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"E/A-Fehler"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Fehler beim Parsen der VCard"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Keine VCard-Datei auf SD-Karte gefunden"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Es wurde kein gültiger VCard-Eintrag für Ihre Auswahl gefunden."</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"VCard-Datei auswählen"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Wählen Sie eine VCard-Datei für den Import aus."</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"VCard wird gelesen."</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"VCard-Dateien werden gelesen."</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"VCard-Daten werden importiert."</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Fehler beim Lesen der VCard-Daten"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"VCard-Daten konnten nicht gelesen werden."\n"Grund für den Fehler: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Die vCard konnte aus einem unbekannten Grund nicht geparst werden."</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Beim Parsen der vCard ist ein Fehler aufgetreten. Obwohl die vCard anscheinend ein gültiges Format aufweist, wird sie von der aktuellen Implementierung nicht unterstützt."</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Keine VCard-Datei auf der SD-Karte gefunden"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Es wurde kein gültiger vCard-Eintrag für Ihre Auswahl gefunden."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Fehler beim Import einer oder mehrerer Dateien (%s)"</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Unbekannter Fehler"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"vCard-Datei auswählen"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Wählen Sie eine vCard-Datei für den Import aus."</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"vCard wird gelesen."</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"vCard-Dateien werden gelesen."</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"vCard-Daten werden importiert."</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Fehler beim Lesen der vCard-Daten"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"vCard konnte nicht gelesen werden."\n"Fehlerursache: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> von <xliff:g id="TOTAL_NUMBER">%s</xliff:g> Kontakten"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> von <xliff:g id="TOTAL_NUMBER">%s</xliff:g> Dateien"</string>
+ <string name="export_all_contacts" msgid="2873892623335194071">"Alle Kontakte"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Lokal gespeicherte Kontakte"</string>
<string name="export_contact_list" msgid="3165097742175874384">"Kontakte exportieren"</string>
- <string name="confirm_export_title" msgid="1693047909433122854">"Bestätigung des Exports"</string>
- <string name="confirm_export_message" msgid="63482084706768079">"Soll Ihre Kontaktliste in \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\" exportiert werden?"</string>
- <string name="exporting_contact_failed_title" msgid="1455264422455075858">"Fehler beim Exportieren der Kontaktdaten"</string>
- <string name="exporting_contact_failed_message" msgid="1426451081541603512">"Kontaktdaten konnten nicht exportiert werden."\n"Grund für den Fehler: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
- <string name="fail_reason_too_many_vcard" msgid="5416992255233341607">"Zu viele VCard-Daten auf der SD-Karte"</string>
- <string name="fail_reason_too_long_filename" msgid="7105223965196949065">"Der Dateiname \"<xliff:g id="FILENAME">%s</xliff:g>\" ist zu lang."</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Export bestätigen"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Soll Ihre Kontaktliste wirklich an \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\" exportiert werden?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Fehler beim Exportieren von Kontaktdaten"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Fehler beim Exportieren der Kontaktdaten."\n"Fehlerursache: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Es ist kein exportierbarer Kontakt vorhanden"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Zu viele vCard-Dateien auf der SD-Karte"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Erforderlicher Dateiname ist zu lang (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Zielverzeichnis \"<xliff:g id="DIR_NAME">%s</xliff:g>\" kann nicht geöffnet oder erstellt werden."</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"Kontaktdaten werden exportiert."</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"Kontaktdaten werden in \"<xliff:g id="FILE_NAME">%s</xliff:g>\" exportiert."</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Exportprogramm konnte nicht initialisiert werden: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Fehler beim Exportieren: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Fehler bei der Ermittlung von Datenbank-Informationen"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Es ist kein exportierbarer Kontakt vorhanden. Möglicherweise können Sie nicht exportierbare Daten auswählen."</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"Das Programm zum Erstellen der vCard wurde nicht richtig initialisiert."</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" konnte nicht geöffnet werden: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> von <xliff:g id="TOTAL_NUMBER">%s</xliff:g> Kontakten"</string>
<string name="search_settings_description" msgid="2675223022992445813">"Namen Ihrer Kontakte"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"2 Sekunden Pause hinzufügen"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Warten hinzufügen"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Wählen"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Anrufen mit"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Textnachricht schreiben mit"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Diese Auswahl speichern"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Für diese Aktion wurde keine Anwendung gefunden."</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Diese Auswahl speichern"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Unbekannt"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Konten"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importieren/Exportieren"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Kontakte importieren/exportieren"</string>
+ <string name="menu_share" msgid="943789700636542260">"Freigeben"</string>
+ <string name="share_via" msgid="563121028023030093">"Kontakt freigeben über"</string>
+ <string name="share_error" msgid="4374508848981697170">"Dieser Kontakt kann nicht freigegeben werden."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Name"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Alias"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Firma/Organisation"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Termin"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"P"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"A"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"S"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Dieser Kontakt ist schreibgeschützt."</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Mehr"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Hauptname"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Neuen Kontakt unter Konto erstellen"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Synchronisierungsgruppe entfernen"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Synchronisierungsgruppe hinzufügen"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Weitere Gruppen..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Alle weiteren Kontakte"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Alle Kontakte"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Wenn \"<xliff:g id="GROUP">%s</xliff:g>\" aus der Synchronisierung entfernt wird, werden auch alle nicht gruppierten Kontakte aus der Synchronisierung entfernt."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Nur Telefon (nicht synchronisiert)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Anzeigename"</string>
+ <string name="call_custom" msgid="7756571794763171802">"<xliff:g id="CUSTOM">%s</xliff:g> anrufen"</string>
+ <string name="call_home" msgid="1990519474420545392">"Anruf (privat)"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Anruf (mobil)"</string>
+ <string name="call_work" msgid="5328785911463744028">"Anruf (Arbeit)"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Anruf (Fax, Arbeit)"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Faxanruf (privat)"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Anruf (Pager)"</string>
+ <string name="call_other" msgid="5605584621798108205">"Anruf (sonstige)"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Rückrufnummer anrufen"</string>
+ <string name="call_car" msgid="3280537320306436445">"Anruf (Auto)"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Anruf (Firmenhauptnummer)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"ISDN-Nummer anrufen"</string>
+ <string name="call_main" msgid="6082900571803441339">"Hauptnummer anrufen"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Andere Faxnummer anrufen"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Anruf (Mobilfunk)"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Telexnummer anrufen"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"TTY/TDD anrufen"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Mobilfunknummer (geschäftlich) anrufen"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Pager (beruflich) anrufen"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"<xliff:g id="ASSISTANT">%s</xliff:g> anrufen"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Anruf (MMS)"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Text <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Text (privat)"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Text (mobil)"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Text (Arbeit)"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Text (Fax, Arbeit)"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Text (Fax, privat)"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Text-Pager"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Text (sonstige)"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Textnachricht an Rückrufnummer"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Text (Auto)"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Text (Firmenhauptnummer)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Textnachricht an ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Textnachricht an Hauptnummer"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Textnachricht an andere Faxnummer"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Text (Mobilfunk)"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Textnachricht an Telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Textnachricht an TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Textnachricht an Mobilfunknummer (geschäftlich)"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Textnachricht an Pager (geschäftlich)"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Textnachricht an <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Text (MMS)"</string>
+ <string name="email_home" msgid="8573740658148184279">"E-Mail-Startseite"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-Mail (mobil)"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-Mail (Arbeit)"</string>
+ <string name="email_other" msgid="8093933498541795832">"E-Mail (sonstige)"</string>
+ <string name="email_custom" msgid="7548003991586214105">"E-Mail <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-Mail"</string>
+ <string name="map_home" msgid="1243547733423343982">"Privatadresse anzeigen"</string>
+ <string name="map_work" msgid="1360474076921878088">"Arbeitsadresse anzeigen"</string>
+ <string name="map_other" msgid="5560707927535653892">"Sonstige Adressen anzeigen"</string>
+ <string name="map_custom" msgid="6184363799976265281">"<xliff:g id="CUSTOM">%s</xliff:g>-Adresse anzeigen"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chat über AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chat über Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chat über Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chat über Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chat über QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chat über Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chat über ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chat über Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Straße"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Postfach"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Nachbarschaft"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Stadt"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Staat"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postleitzahl"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Land"</string>
+ <string name="name_given" msgid="1687286314106019813">"Vorname"</string>
+ <string name="name_family" msgid="3416695586119999058">"Nachname"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Namenpräfix"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Zweiter Vorname"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Namensuffix"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Phonetischer Vorname"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Phonetischer zweiter Vorname"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Phonetischer Nachname"</string>
+ <string name="split_label" msgid="8262112659919449087">"Teilen"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Aus diesen Daten einen eigenen Kontakt erstellen"</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Von <xliff:g id="SOURCE">%1$s</xliff:g>-Konto: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g>-Kontakt"</string>
+ <string name="from_account_format" msgid="687567483928582084">"von <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Dieses Foto verwenden"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g>-Kontaktinformationen können auf diesem Gerät nicht bearbeitet werden."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Keine Zusatzinformationen zu diesem Kontakt"</string>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 2e89a34..0fd7790 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -16,18 +16,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Επαφές"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Πρόγρ.κλήσ."</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Τηλέφωνο"</string>
<string name="shortcutContact" msgid="749243779392912958">"Επαφή"</string>
- <!-- no translation found for shortcutDialContact (7165340343023469996) -->
- <skip />
- <!-- no translation found for shortcutMessageContact (3025782962770298900) -->
- <skip />
- <!-- no translation found for shortcutActivityTitle (6642877210643565436) -->
- <skip />
- <!-- no translation found for callShortcutActivityTitle (6065749861423648991) -->
- <skip />
- <!-- no translation found for messageShortcutActivityTitle (3084542316620335911) -->
- <skip />
+ <string name="shortcutDialContact" msgid="746622101599186779">"Άμεση κλήση"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Άμεσο μήνυμα"</string>
+ <string name="shortcutActivityTitle" msgid="6642877210643565436">"Επιλογή μιας συντόμευσης επαφών"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"Επιλογή ενός αριθμού για κλήση"</string>
+ <string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Επιλογή ενός αριθμού για μήνυμα"</string>
<string name="starredList" msgid="4817256136413959463">"Με αστέρι"</string>
<string name="frequentList" msgid="7154768136473953056">"Συχνές"</string>
<string name="strequentList" msgid="5640192862059373511">"Αγαπ."</string>
@@ -45,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Εμφάνιση γραμμωτού κώδικα"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Επεξεργασία επαφής"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Διαγραφή επαφής"</string>
- <string name="menu_call" msgid="7359207953236681606">"Κλήση"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Αποστολή SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Κλήση επαφής"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Αποστολή μηνύματος κειμένου σε επαφή"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Διεύθυνση στον χάρτη"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Ορισμός προεπιλεγμένου αριθμού"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Ορισμός διεύθυνσης ηλεκτρονικού ταχυδρομείου ως προεπιλογή"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Διαχωρισμός"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Διαχωρισμός επαφής"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Οι επαφές διαχωρίστηκαν"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Διαχωρισμός επαφής"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Είστε βέβαιοι ότι θέλετε να διαχωρίσετε αυτή τη μία επαφή σε πολλές επαφές: μία για κάθε σύνολο στοιχείων επικοινωνίας που προστέθηκε σε αυτήν;"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Σύνδεση"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Εμφάνιση πηγών"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Απόκρυψη πηγών"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Σύνδεση επαφής"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Ένωση επαφών"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Επιλέξτε την επαφή που θέλετε να ενώσετε με το χρήστη <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Εμφάνιση όλων των επαφών"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Προτεινόμενες επαφές"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Όλες οι επαφές"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Οι επαφές συνδέθηκαν"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Επιλογές"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Επιλογές"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Διαγραφή"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Δεν μπορείτε να διαγράψετε επαφές από λογαριασμούς οι οποίοι είναι μόνο για ανάγνωση, αλλά μπορείτε να τις αποκρύψετε στις λίστες επαφών σας."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Αυτή η επαφή περιέχει πληροφορίες από πολλούς λογαριασμούς. Θα γίνει απόκρυψη και όχι διαγραφή των πληροφοριών που προέρχονται από λογαριασμούς μόνο για ανάγνωση στις λίστες επαφών σας."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Εάν διαγράψετε αυτήν την επαφή, θα γίνει διαγραφή των πληροφοριών από πολλούς λογαριασμούς."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Αυτή η επαφή θα διαγραφεί."</string>
<string name="menu_done" msgid="796017761764190697">"Τέλος"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Επαναφορά"</string>
@@ -60,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Φωνητική"</string>
<string name="label_notes" msgid="8337354953278341042">"Σημειώσεις"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Ήχος κλήσης"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Ομάδες"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Επεξεργασία ομάδων"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Όνομα και επίθετο"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Φωνητικό όνομα"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Εταιρεία"</string>
@@ -69,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Αριθμός τηλεφώνου"</string>
<string name="ghostData_email" msgid="6184537075551565919">"Διεύθυνση ηλεκτρονικού ταχυδρομείου"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Ταχυδρομική διεύθυνση"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Προβολή ομάδας"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Η επαφή δεν υπάρχει."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Δημιουργία νέας επαφής"</string>
<string name="selectLabel" msgid="4255424123394910733">"Επιλογή ετικέτας"</string>
@@ -85,29 +105,45 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Δεν υπάρχουν διαθέσιμες εικόνες στο τηλέφωνο."</string>
<string name="attachToContact" msgid="8820530304406066714">"Εικονίδιο επαφής"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Προσαρμοσμένο όνομα ετικέτας"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Προβολή ομάδας"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Επιλογές προβολής"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Επιλογές προβολής"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Επεξ. ομάδ. συγχρ."</string>
<string name="importFromSim" msgid="8383900146531125319">"Εισαγωγή επαφών"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Αποστολή κλήσεων απευθείας στον αυτόματο τηλεφωνητή"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Οι κλήσεις στέλνονται απευθείας στον αυτόματο τηλεφωνητή."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Προεπιλογή"</string>
<string name="addPicture" msgid="1594679312161537678">"Προσθήκη εικονιδίου"</string>
+ <!-- no translation found for changePicture (2943329047610967714) -->
+ <skip />
<string name="removePicture" msgid="3041230993155966350">"Κατάργηση εικονιδίου"</string>
<string name="noContacts" msgid="8579310973261953559">"Δεν υπάρχουν επαφές."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Δεν βρέθηκαν επαφές που να αντιστοιχούν."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Δεν υπάρχουν επαφές με αριθμούς τηλεφώνου."</string>
<string name="noFavorites" msgid="812766386743315815">"Δεν υπάρχουν αγαπημένα."</string>
<string name="select_group_title" msgid="7955698611959835612">"Ομάδες"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Η ομάδα σας \"<xliff:g id="GROUPNAME">%s</xliff:g>\" είναι κενή."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Όλες οι επαφές"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Μόνο επαφές με τηλέφωνα"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Να προβάλλονται μόνο οι επαφές που διαθέτουν αριθμό τηλεφώνου"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Επιλογή επαφών προς προβολή"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> επαφές"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> επαφές, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> με τηλέφωνα"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Συγχρονισμός όλων των επαφών"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Οι επαφές μου"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Οι επαφές μου"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Επαφές με αριθμούς τηλεφώνου"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Με αστέρι στο Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Αποθήκευση επαφής…"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Αποθήκευση επιλογών προβολής…"</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Η επαφή δημιουργήθηκε."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Η επαφή αποθηκεύτηκε."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Σφάλμα, δεν ήταν δυνατή η αποθήκευση αλλαγών επαφής."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Αριθμός κλήσης"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Αριθμοί τηλεφώνου"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Αποστολή SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Αποστολή μηνύματος κειμένου"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"Διευθ.ηλεκτρ.ταχυδρ."</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Αποστολή άμεσου μηνύματος"</string>
@@ -115,17 +151,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Διεύθυνση στον χάρτη"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Διευθύνσεις ταχυδρομείου"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Εταιρείες"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Ομάδες"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Άλλες πληροφορίες"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Άλλες επιλογές"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Περισσότερα"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Εμφάνιση 1 επαφής με αριθμό τηλεφώνου"</item>
+ <item quantity="other" msgid="6133262880804110289">"Εμφάνιση <xliff:g id="COUNT">%d</xliff:g> επαφών με αριθμούς τηλεφώνων"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Δεν υπάρχουν ορατές επαφές με αριθμούς τηλεφώνων"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Εμφάνιση 1 επαφής"</item>
+ <item quantity="other" msgid="2865867557378939630">"Εμφάνιση <xliff:g id="COUNT">%d</xliff:g> επαφών"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Δεν υπάρχουν ορατές επαφές"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"Βρέθηκε 1 επαφή"</item>
+ <item quantity="other" msgid="7752927996850263152">"Βρέθηκαν <xliff:g id="COUNT">%d</xliff:g> επαφές"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Δεν βρέθηκε η επαφή"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Κοινωνικά"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Επαφές"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Αγαπ."</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Πρόγρ. κλήσ."</string>
- <string name="recentCallsIconLabel" msgid="1419116422359067949">"Αρχ.καταγρ.κλήσ."</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Τηλέφωνο"</string>
+ <string name="recentCallsIconLabel" msgid="1419116422359067949">"Αρχείο"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Όλες οι επαφές"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Επαφές με αστέρι"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Επαφές με αριθμούς τηλεφώνου"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Αποστολή μηνύματος SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Αποστολή μηνύματος κειμένου"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Κλήση <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Επεξεργασία αριθμού πριν την κλήση"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Προσθήκη στις επαφές"</string>
@@ -133,6 +186,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Εκκαθάριση αρχείου καταγραφής κλήσεων"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Το αρχείο καταγραφής κλήσεων είναι κενό."</string>
<string name="imei" msgid="3045126336951684285">"Αριθμός ΙΜΕΙ"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Αυτόματος τηλεφωνητής"</string>
<string name="unknown" msgid="740067747858270469">"Άγνωστος"</string>
<string name="private_num" msgid="6374339738119166953">"Απόκρυψη"</string>
@@ -142,10 +196,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Φόρτωση από κάρτα SIM…"</string>
<string name="simContacts_title" msgid="27341688347689769">"Επαφές στην κάρτα SIM"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Συγχρονίστε τις επαφές σας Google!"</font>" "\n"Μετά το συγχρονισμό στο τηλέφωνό σας, οι επαφές σας θα είναι διαθέσιμες όπου κι αν πάτε.."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Δεν έχετε επαφές."\n\n"Για να προσθέσετε επαφές, πατήστε "<font fgcolor="#ffffffff"><b>"Μενού"</b></font>" και επιλέξτε:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Νέα επαφή"</b></font>" για να δημιουργήσετε μια νέα επαφή από την αρχή"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Εισαγωγή επαφών"</b></font>" για να προσθέσετε επαφές από την κάρτα SIM"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Δεν έχετε επαφές."\n\n"Για να προσθέσετε επαφές, πατήστε "<font fgcolor="#ffffffff"><b>"Μενού"</b></font>" και επιλέξτε:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Επεξεργασία ομάδων συγχρονισμού"</b></font>" για να προσθέσετε από ένα νέο ή υπάρχοντα λογαριασμό Google"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Νέα επαφή"</b></font>" για να δημιουργήσετε μια νέα επαφή από την αρχή"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Εισαγωγή επαφών"</b></font>" για να προσθέσετε επαφές από την κάρτα SIM"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Δεν έχετε επαφές προς προβολή."\n\n"Για προσθήκη επαφών, πατήστε "<font fgcolor="#ffffffff"><b>"Μενού"</b></font>" και αγγίξτε:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Λογαριασμοί"</b></font>" για προσθήκη ή διαμόρφωση λογαριασμού με επαφές που μπορείτε να συγχρονίσετε στο τηλέφωνο"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Νέα επαφή"</b></font>" για δημιουργία νέας επαφής από το μηδέν"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Εισαγωγή/Εξαγωγή"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Δεν έχετε επαφές προς προβολή. (Αν προσθέσατε κάποιον λογαριασμό μόλις τώρα, θα χρειαστούν λίγα λεπτά έως ότου γίνει ο συγχρονισμός.)"\n\n"Για την προσθήκη επαφών, πατήστε "<font fgcolor="#ffffffff"><b>"Μενού"</b></font>" και αγγίξτε την επιλογή:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Λογαριασμοί"</b></font>" για την προσθήκη ή διαμόρφωση λογαριασμού με επαφές τις οποίες μπορείτε να συγχρονίσετε στο τηλέφωνο"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Επιλογές προβολής"</b></font>" για να αλλάξετε τις επαφές που είναι ορατές"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Νέα επαφή"</b></font>" για δημιουργία νέας επαφής από το μηδέν"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Εισαγωγή/Εξαγωγή"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Δεν έχετε επαφές προς προβολή."\n\n"Για προσθήκη επαφών, πατήστε "<font fgcolor="#ffffffff"><b>"Μενού"</b></font>" και αγγίξτε την επιλογή:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Λογαριασμοί"</b></font>" για προσθήκη ή διαμόρφωση λογαριασμού με επαφές που μπορείτε να συγχρονίσετε στο τηλέφωνο"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Νέα επαφή"</b></font>" για δημιουργία νέας επαφής από το μηδέν"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Εισαγωγή/Εξαγωγή"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Δεν έχετε επαφές προς προβολή. (Αν προσθέσατε κάποιον λογαριασμό μόλις τώρα, θα χρειαστούν λίγα λεπτά έως ότου γίνει ο συγχρονισμός.)"\n\n"Για την προσθήκη επαφών, πατήστε "<font fgcolor="#ffffffff"><b>"Μενού"</b></font>" και αγγίξτε την επιλογή:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Λογαριασμοί"</b></font>" για την προσθήκη ή διαμόρφωση λογαριασμού με επαφές τις οποίες μπορείτε να συγχρονίσετε στο τηλέφωνο"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Προβολή επιλογών"</b></font>" για να αλλάξετε τις επαφές που είναι ορατές"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Νέα επαφή"</b></font>" για δημιουργία νέας επαφής από το μηδέν"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Εισαγωγή/Εξαγωγή"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Δεν έχετε αγαπημένα."\n\n"Για προσθήκη επαφής στη λίστα των αγαπημένων σας:"\n\n" "<li>"Αγγίξτε την καρτέλα "<b>"Επαφές"</b>\n</li>" "\n<li>"Αγγίξτε το όνομα της επαφής που θέλετε να προσθέσετε στα αγαπημένα σας"\n</li>" "\n<li>"Αγγίξτε το αστέρι πλάι στο όνομα της επαφής"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Επιλογή ομάδων για συγχρονισμό"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Όλες οι επαφές"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Όλες οι επαφές"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Με αστέρι"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Τηλέφωνα"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Χρησιμοποιήστε το πληκτρολόγιο αφής ηχητικών τόνων"</string>
@@ -176,84 +233,191 @@
<string name="returnCall" msgid="8171961914203617813">"Επιστροφή κλήσης"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> λεπτά <xliff:g id="SECONDS">%s</xliff:g> δευτερόλεπτα"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Συχνές κλήσεις"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Προσθήκη επαφής"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Προσθήκη επαφής"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Προσθήκη του \"<xliff:g id="EMAIL">%s</xliff:g>\" στις επαφές;"</string>
- <!-- no translation found for description_image_button_one (1740638037139856139) -->
- <skip />
- <!-- no translation found for description_image_button_two (5882638439003731308) -->
- <skip />
- <!-- no translation found for description_image_button_three (8709731759376015180) -->
- <skip />
- <!-- no translation found for description_image_button_four (3530239685642246130) -->
- <skip />
- <!-- no translation found for description_image_button_five (1182465427501188413) -->
- <skip />
- <!-- no translation found for description_image_button_six (2093656269261415475) -->
- <skip />
- <!-- no translation found for description_image_button_seven (2450357020447676481) -->
- <skip />
- <!-- no translation found for description_image_button_eight (6969435115163287801) -->
- <skip />
- <!-- no translation found for description_image_button_nine (7857248695662558323) -->
- <skip />
- <!-- no translation found for description_image_button_star (3365919907520767866) -->
- <skip />
- <!-- no translation found for description_image_button_zero (4133108949401820710) -->
- <skip />
- <!-- no translation found for description_image_button_pound (3039765597595889230) -->
- <skip />
- <string name="no_sdcard_title" msgid="6455416795090113715">"Δεν υπάρχει κάρτα SD"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Δεν ανιχνεύθηκε κάρτα SD"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Αναζήτηση VCard"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Όλα"</string>
+ <string name="description_image_button_one" msgid="1740638037139856139">"ένα"</string>
+ <string name="description_image_button_two" msgid="5882638439003731308">"δύο"</string>
+ <string name="description_image_button_three" msgid="8709731759376015180">"τρία"</string>
+ <string name="description_image_button_four" msgid="3530239685642246130">"τέσσερα"</string>
+ <string name="description_image_button_five" msgid="1182465427501188413">"πέντε"</string>
+ <string name="description_image_button_six" msgid="2093656269261415475">"έξι"</string>
+ <string name="description_image_button_seven" msgid="2450357020447676481">"επτά"</string>
+ <string name="description_image_button_eight" msgid="6969435115163287801">"οχτώ"</string>
+ <string name="description_image_button_nine" msgid="7857248695662558323">"εννιά"</string>
+ <string name="description_image_button_star" msgid="3365919907520767866">"αστέρι"</string>
+ <string name="description_image_button_zero" msgid="4133108949401820710">"μηδέν"</string>
+ <string name="description_image_button_pound" msgid="3039765597595889230">"σύμβολο δίεσης"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Δεν υπάρχει κάρτα SD"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Δεν ανιχνεύθηκε κάρτα SD"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Αναζήτηση κάρτας vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Από πού θέλετε να εισάγετε επαφές;"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"Κάρτα SIM"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"Κάρτα SD"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Εισαγωγή όλων των αρχείων VCard"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Εισαγωγή ενός αρχείου VCard"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Αναζήτηση δεδομένων VCard στην κάρτα SD"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Η σάρωση της κάρτας SD απέτυχε"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Η σάρωση της κάρτας SD απέτυχε"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Εισαγωγή από κάρτα SIM"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Εισαγωγή από κάρτα SD"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Εξαγωγή σε κάρτα SD"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Εισαγωγή ενός αρχείου VCard"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Εισαγωγή πολλαπλών αρχείων vCard"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Εισαγωγή όλων των αρχείων vCard"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Αναζήτηση για δεδομένα vCard στην κάρτα SD"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Η σάρωση της κάρτας SD απέτυχε"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Η σάρωση της κάρτας SD απέτυχε (Αιτία:\"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Σφάλμα I/O"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Η ανάλυση του VCard απέτυχε"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Δεν βρέθηκε αρχείο VCard στην κάρτα SD"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Δεν βρέθηκε έγκυρη καταχώρηση VCard για την επιλογή σας"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Επιλογή αρχείου VCard"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Επιλέξτε ένα αρχείο VCard για εισαγωγή"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Ανάγνωση VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Ανάγνωση αρχείου (ων) VCard"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Εισαγωγή δεδομένων VCard"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Η ανάγνωση των δεδομένων VCard απέτυχε"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"Δεν ήταν δυνατή η ανάγνωση των δεδομένων VCard"\n"Αιτία αποτυχίας: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Η ανάλυση της κάρτας vCard απέτυχε εξαιτίας μη αναμενόμενου συμβάντος"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Αν και το VCard φαίνεται να βρίσκεται σε έγκυρη μορφή, η ανάλυσή του απέτυχε, εφόσον η τρέχουσα εφαρμογή δεν το υποστηρίζει"</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Δεν βρέθηκε αρχείο VCard στην κάρτα SD"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Δεν βρέθηκε έγκυρη καταχώρηση VCard για την επιλογή σας"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Η εισαγωγή ενός ή περισσοτέρων αρχείων απέτυχε (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Άγνωστο σφάλμα"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Επιλογή αρχείου vCard"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Επιλέξτε ένα αρχείο vCard για εισαγωγή"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Ανάγνωση vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Ανάγνωση αρχείου(ων) vCard"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Εισαγωγή δεδομένων vCard"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Η ανάγνωση των δεδομένων vCard απέτυχε"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Δεν ήταν δυνατή η ανάγνωση της κάρτας vCard."\n"Αίτια αποτυχίας: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> από <xliff:g id="TOTAL_NUMBER">%s</xliff:g> επαφές"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> από <xliff:g id="TOTAL_NUMBER">%s</xliff:g> αρχεία"</string>
- <!-- no translation found for export_contact_list (3165097742175874384) -->
- <skip />
- <!-- no translation found for confirm_export_title (1693047909433122854) -->
- <skip />
- <!-- no translation found for confirm_export_message (63482084706768079) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_title (1455264422455075858) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_message (1426451081541603512) -->
- <skip />
- <!-- no translation found for fail_reason_too_many_vcard (5416992255233341607) -->
- <skip />
- <!-- no translation found for fail_reason_too_long_filename (7105223965196949065) -->
- <skip />
- <!-- no translation found for fail_reason_cannot_open_destination_dir (1739293936432987758) -->
- <skip />
- <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
- <skip />
- <!-- no translation found for exporting_contact_list_message (5640326540405486055) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_initialize_exporter (4943708332700987376) -->
- <skip />
- <!-- no translation found for fail_reason_error_occurred_during_export (2151165129433831202) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_open_file (4013520943128739511) -->
- <skip />
- <!-- no translation found for exporting_contact_list_progress (560522409559101193) -->
- <skip />
- <!-- no translation found for search_settings_description (2675223022992445813) -->
- <skip />
+ <string name="export_all_contacts" msgid="2873892623335194071">"Όλες οι επαφές"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Τοπικά αποθηκευμένες επαφές"</string>
+ <string name="export_contact_list" msgid="3165097742175874384">"Εξαγωγή επαφών"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Επιβεβαίωση\nεξαγωγής"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Είστε σίγουροι ότι θέλετε να εξαγάγετε τη λίστα των επαφών σας στο \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\";"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Αποτυχία εξαγωγής δεδομένων επαφής"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Αποτυχία εξαγωγής δεδομένων επαφής."\n"Αιτία αποτυχίας: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Δεν υπάρχει επαφή με δυνατότητα εξαγωγής"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Υπερβολικά μεγάλος όγκος αρχείων VCard στην κάρτα SD"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Το απαιτούμενο όνομα αρχείου είναι υπερβολικά μεγάλο (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Δεν είναι δυνατό το άνοιγμα ή η δημιουργία του καταλόγου προορισμού\"<xliff:g id="DIR_NAME">%s</xliff:g>\""</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Εξαγωγή δεδομένων επαφών"</string>
+ <string name="exporting_contact_list_message" msgid="5640326540405486055">"Εξαγωγή δεδομένων επαφών προς \"<xliff:g id="FILE_NAME">%s</xliff:g>\""</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Δεν ήταν δυνατή η εκκίνηση της εξαγωγής: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Προέκυψε σφάλμα κατά την εξαγωγή: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Αποτυχία λήψης πληροφοριών βάσης δεδομένων"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Δεν υπάρχει επαφή με δυνατότητα εξαγωγής. Ενδέχεται να επιλέξατε μη εξαγώγιμα δεδομένα"</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"Δεν έχει γίνει σωστή εκκίνηση του προγράμματος σύνθεσης της vCard"</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Δεν ήταν δυνατό το άνοιγμα του \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> από <xliff:g id="TOTAL_NUMBER">%s</xliff:g> επαφές"</string>
+ <string name="search_settings_description" msgid="2675223022992445813">"Ονόματα ων επαφών σας"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Προσθήκη παύσης 2 δευτερολέπτων"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Προσθήκη αναμονής"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Κλήση"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Κλήση με τη χρήση"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Αποστολή κειμένου με χρήση"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Διατήρηση αυτής της ρύθμισης"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Δεν βρέθηκε εφαρμογή για τη διαχείριση αυτής της ενέργειας"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Διατήρηση αυτής της επιλογής"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Άγνωστος"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Λογαριασμοί"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Εισαγωγή/Εξαγωγή"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Εισαγωγή/Εξαγωγή επαφών"</string>
+ <string name="menu_share" msgid="943789700636542260">"Κοινή χρήση"</string>
+ <string name="share_via" msgid="563121028023030093">"Κοινή χρήση μέσω"</string>
+ <string name="share_error" msgid="4374508848981697170">"Δεν είναι δυνατή η κοινή χρήση αυτής της επαφής."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Όνομα"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Ψευδώνυμο"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Οργανισμός"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Ιστότοπος"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Συμβάν"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"Ο"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"Κ"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"Ε"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"Β"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"Α"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Αυτή η επαφή είναι μόνο για ανάγνωση"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Περισσότερα"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Κύριο όνομα"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Δημιουργία επαφής\nστον λογαριασμό"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Κατάργηση ομάδας συγχρονισμού"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Προσθήκη ομάδας συγχρονισμού"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Περισσότερες ομάδες…"</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Όλες οι άλλες επαφές"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Όλες οι επαφές"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Η κατάργηση της ομάδας \"<xliff:g id="GROUP">%s</xliff:g>\" από τον συγχρονισμό θα καταργήσει επίσης και τις επαφές χωρίς ομαδοποίηση από τον συγχρονισμό."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Μόνο στο τηλέφωνο (Χωρίς συγχρονισμό)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Προβολή ονόματος"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Κλήση <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Κλήση οικίας"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Κλήση κινητής συσκευής"</string>
+ <string name="call_work" msgid="5328785911463744028">"Κλήση εργασίας"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Κλήση φαξ εργασίας"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Κλήση φαξ οικίας"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Κλήση βομβητή"</string>
+ <string name="call_other" msgid="5605584621798108205">"Κλήση άλλο"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Κλήση αριθμού επανάκλησης"</string>
+ <string name="call_car" msgid="3280537320306436445">"Κλήση τηλεφώνου αυτοκινήτου"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Κλήση κύριας εταιρικής γραμμής"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Κλήση ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Κλήση κύριου αριθμού"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Κλήση άλλου φαξ"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Κλήση πομπού"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Κλήση σε τηλέτυπο"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Κλήση σε τηλέφωνο TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Κλήση κινητού τηλεφώνου εργασίας"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Κλήση βομβητή εργασίας"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Κλήση <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Κλήση MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Αποστολή μηνύματος κειμένου προς <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Αποστολή μηνύματος κειμένου προς οικία"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Αποστολή μηνύματος κειμένου προς κινητή συσκευή"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Αποστολή μηνύματος κειμένου προς εργασία"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Αποστολή μηνύματος κειμένου προς φαξ εργασίας"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Αποστολή μηνύματος κειμένου προς φαξ οικίας"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Αποστολή μηνύματος κειμένου προς βομβητή"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Αποστολή μηνύματος κειμένου προς άλλο"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Αποστολή μηνύματος κειμένου σε αριθμό επανάκλησης"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Αποστολή μηνύματος κειμένου προς τηλέφωνο αυτοκινήτου"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Αποστολή μηνύματος κειμένου προς κύρια εταιρική γραμμή"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Αποστολή κειμένου σε ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Αποστολή μηνύματος κειμένου προς κύριο αριθμό"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Αποστολή μηνύματος κειμένου προς άλλο φαξ"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Αποστολή μηνύματος κειμένου προς πομπό"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Αποστολή μηνύματος κειμένου σε τηλέτυπο"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Αποστολή μηνύματος κειμένου προς τηλέφωνο TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Αποστολή μηνύματος κειμένου προς κινητό τηλέφωνο εργασίας"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Αποστολή μηνύματος κειμένου προς βομβητή εργασίας"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Αποστολή μηνύματος κειμένου προς <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Αποστολή μηνύματος κειμένου ως MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"Αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου προς οικία"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου προς κινητή συσκευή"</string>
+ <string name="email_work" msgid="2807430017302722689">"Αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου προς εργασία"</string>
+ <string name="email_other" msgid="8093933498541795832">"Αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου προς άλλο"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου προς <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Διεύθυνση ηλεκτρονικού ταχυδρομείου"</string>
+ <string name="map_home" msgid="1243547733423343982">"Προβολή διεύθυνσης οικίας"</string>
+ <string name="map_work" msgid="1360474076921878088">"Προβολή διεύθυνσης εργασίας"</string>
+ <string name="map_other" msgid="5560707927535653892">"Προβολή άλλων διευθύνσεων"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Προβολή διεύθυνσης <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Συζήτηση μέσω AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Συζήτηση μέσω Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Συζήτηση μέσω Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Συζήτηση μέσω Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Συζήτηση μέσω QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Συζήτηση μέσω Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Συζήτηση μέσω ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Συζήτηση μέσω Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Συζήτηση"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Οδός"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Ταχυδρομική θυρίδα"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Γειτονιά"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Πόλη"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Πολιτεία"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Ταχυδρομικός κώδικας"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Χώρα"</string>
+ <string name="name_given" msgid="1687286314106019813">"Όνομα"</string>
+ <string name="name_family" msgid="3416695586119999058">"Επίθετο"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Πρόθεμα ονόματος"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Πατρώνυμο"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Επίθημα ονόματος"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Φωνητική μορφή ονόματος"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Φωνητική γραφή ονόματος πατρός"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Φωνητική γραφή επιθέτου"</string>
+ <string name="split_label" msgid="8262112659919449087">"Διαχωρισμός"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Δημιουργήστε νέα επαφή για αυτά τα δεδομένα."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Από λογαριασμό στο <xliff:g id="SOURCE">%1$s</xliff:g>: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> επαφή"</string>
+ <string name="from_account_format" msgid="687567483928582084">"από <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Χρήση αυτής της φωτογραφίας"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"Τα στοιχεία επικοινωνίας της επαφής <xliff:g id="SOURCE">%1$s</xliff:g> δεν μπορούν να υποβληθούν σε επεξεργασία σε αυτήν τη συσκευή."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Δεν υπάρχουν πρόσθετες πληροφορίες για αυτήν την επαφή"</string>
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index d233c6a..07ffe85 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -16,18 +16,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Contactos"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Marcador"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Teléfono"</string>
<string name="shortcutContact" msgid="749243779392912958">"Contacto"</string>
- <!-- no translation found for shortcutDialContact (7165340343023469996) -->
- <skip />
- <!-- no translation found for shortcutMessageContact (3025782962770298900) -->
- <skip />
- <!-- no translation found for shortcutActivityTitle (6642877210643565436) -->
- <skip />
- <!-- no translation found for callShortcutActivityTitle (6065749861423648991) -->
- <skip />
- <!-- no translation found for messageShortcutActivityTitle (3084542316620335911) -->
- <skip />
+ <string name="shortcutDialContact" msgid="746622101599186779">"Marcado directo"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Mensaje directo"</string>
+ <string name="shortcutActivityTitle" msgid="6642877210643565436">"Seleccionar un acceso directo"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"Seleccionar un número para la llamada"</string>
+ <string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Seleccionar un número para el mensaje"</string>
<string name="starredList" msgid="4817256136413959463">"Marcado con asterisco"</string>
<string name="frequentList" msgid="7154768136473953056">"Frecuente"</string>
<string name="strequentList" msgid="5640192862059373511">"Favoritos"</string>
@@ -45,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Mostrar código de barras"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Editar contacto"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Suprimir contacto"</string>
- <string name="menu_call" msgid="7359207953236681606">"Llamar a"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Enviar SMS//MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Llamar al contacto"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Enviar texto al contacto"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Enviar correo electrónico"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Dirección del mapa"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Crear número predeterminado"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Crear correo electrónico predeterminado"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Separar"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Dividir contacto"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Contactos separados"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Separar contacto"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"¿Estás seguro de que deseas separar este contacto individual en varios contactos: uno para cada grupo de información de contacto que se unió a él?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Unirse"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Mostrar fuentes"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Ocultar fuentes"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Unirse al contacto"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Unirse a contactos"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Selecciona el contacto al que quieras unirte con <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Mostrar todos los contactos"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Contactos sugeridos"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Todos los contactos"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Unión de contactos"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Opciones"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Opciones"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Suprimir"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"No puedes borrar contactos desde cuentas de solo lectura, pero puedes ocultar tus listas de contactos."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Este contacto contiene información de varias cuentas. La información de las cuentas de solo lectura se ocultará en tus listas de contactos, pero no se eliminará."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Eliminar este contacto suprimirá la información de mútliples cuentas."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Este contacto se suprimirá."</string>
<string name="menu_done" msgid="796017761764190697">"Finalizado"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Revertir"</string>
@@ -60,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonético"</string>
<string name="label_notes" msgid="8337354953278341042">"Notas"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Tono de llamada"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Grupos"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Editar grupos"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Primero y último"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Nombre fonético"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
@@ -67,8 +86,9 @@
<string name="ghostData_im" msgid="7737174936595812794">"Nombre de MI"</string>
<string name="ghostData_notes" msgid="3044201271296187724">"Mi nota"</string>
<string name="ghostData_phone" msgid="6963153888271466620">"Número de teléfono"</string>
- <string name="ghostData_email" msgid="6184537075551565919">"Dirección de correo electrónico"</string>
+ <string name="ghostData_email" msgid="6184537075551565919">"Dirección de correo elec."</string>
<string name="ghostData_postal" msgid="652611650594951897">"Dirección postal"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Mostrar grupo"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"El contacto no existe."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Crear nuevo contacto"</string>
<string name="selectLabel" msgid="4255424123394910733">"Seleccionar etiqueta"</string>
@@ -85,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"No hay imágenes disponibles en el teléfono."</string>
<string name="attachToContact" msgid="8820530304406066714">"Ícono de contacto"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Nombre personalizado de etiqueta"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Mostrar grupo"</string>
- <string name="syncGroupPreference" msgid="9028361137161162861">"Editar grupos sincroniz."</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Mostrar opciones"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Mostrar opciones"</string>
+ <string name="syncGroupPreference" msgid="9028361137161162861">"Editar grupos sincr."</string>
<string name="importFromSim" msgid="8383900146531125319">"Importar contactos"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Enviar llamadas directamente al correo de voz"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Las llamadas se envían directamente a un correo de voz."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Predeterminado"</string>
<string name="addPicture" msgid="1594679312161537678">"Agregar ícono"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Cambiar icono"</string>
<string name="removePicture" msgid="3041230993155966350">"Eliminar ícono"</string>
<string name="noContacts" msgid="8579310973261953559">"No hay contactos."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"No se encontraron contactos coincidentes."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"No hay contactos con números de teléfono."</string>
<string name="noFavorites" msgid="812766386743315815">"No hay favoritos."</string>
<string name="select_group_title" msgid="7955698611959835612">"Grupos"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Tu grupo \"<xliff:g id="GROUPNAME">%s</xliff:g>\" está vacío."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Todos los contactos"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Sólo contactos con teléfonos"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Mostrar sólo contactos que posean números de teléfono"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Elige contactos para mostrar"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> contactos"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> contactos, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> con teléfonos"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Sincronizar todos los contactos"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Mis contactos"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Mis contactos"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Contactos con números de teléfono"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Marcado con asterisco en Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Guardando contacto..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Guardando opciones de visualización..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Contacto creado."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Contacto guardado."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Error, no se han podido guardar las modificaciones de contacto."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Marcar número"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Números de teléfono"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Enviar SMS//MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Enviar texto"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Enviar correo electrónico"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"Direcciones de correo electr."</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Enviar mensaje instantáneo"</string>
@@ -115,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Dirección del mapa"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Direcciones postales"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organizaciones"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Grupos"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Otra información"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Otras opciones"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Más"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Mostrando 1 contacto con el número de teléfono"</item>
+ <item quantity="other" msgid="6133262880804110289">"Se muestran <xliff:g id="COUNT">%d</xliff:g> contactos con números de teléfono."</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"No hay contactos visibles con números de teléfono."</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Mostrando 1 contacto"</item>
+ <item quantity="other" msgid="2865867557378939630">"Mostrando <xliff:g id="COUNT">%d</xliff:g> contactos"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"No hay contactos visibles"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"Se encontró 1 contacto"</item>
+ <item quantity="other" msgid="7752927996850263152">"Se encontraron <xliff:g id="COUNT">%d</xliff:g> contactos"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"No se ha encontrado este contacto."</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Social"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contactos"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Marcador"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Teléfono"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Regist. de llam."</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Todos los contactos"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Contactos marcados con asterisco"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Contactos con números de teléfono"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Enviar mensaje SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Enviar mensaje de texto"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Llamar a <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Editar número antes de llamar"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Agregar a contactos"</string>
@@ -133,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Borrar registro de llamadas"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"El registro de llamadas está vacío."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Correo de voz"</string>
<string name="unknown" msgid="740067747858270469">"Desconocido"</string>
<string name="private_num" msgid="6374339738119166953">"Número privado"</string>
@@ -142,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Cargando desde tarjeta SIM..."</string>
<string name="simContacts_title" msgid="27341688347689769">"Contactos de tarjeta SIM"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"¡Sincroniza tus contactos de Google!"</font>" "\n" Luego de sincronizar tu teléfono, tus contactos estarán disponibles para ti dondequiera que vayas."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"No tienes ningún contacto."\n\n"Para agregar contactos, presiona "<font fgcolor="#ffffffff"><b>"Menú"</b></font>" y selecciona:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Nuevo contacto"</b></font>" para crear un contacto nuevo desde cero"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar contactos"</b></font>" para agregar contactos desde tu tarjeta SIM"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"No tienes ningún contacto."\n\n"Para agregar contactos, presiona "<font fgcolor="#ffffffff"><b>"Menú"</b></font>" y selecciona:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Editar grupos sincronizados"</b></font>" para agregar desde una cuenta de Google nueva o existente"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nuevo contacto"</b></font>" para crear un contacto nuevo desde cero"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar contactos"</b></font>" para agregar contactos desde tu tarjeta SIM"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"No tienes ningún contacto para mostrar."\n\n"Para agregar contactos, presiona "<font fgcolor="#ffffffff"><b>"Menú"</b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para agregar o configurar una cuenta con contactos que puedes sincronizar en el teléfono"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear tú mismo un contacto nuevo"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"No tienes ningún contacto para mostrar. (Si has agregado una cuenta, la sincronización de contactos puede demorar pocos minutos)."\n\n"Para agregar contactos, presiona "<font fgcolor="#ffffffff"><b>"Menú"</b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para agregar y configurar una cuenta con contactos que puedes sincronizar en el teléfono"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Mostrar opciones"</b></font>" para cambiar los contactos que sean visibles"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear tú mismo un contacto nuevo"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"No tienes ningún contacto para mostrar."\n\n"Para agregar contactos, presiona "<font fgcolor="#ffffffff"><b>"Menú"</b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para agregar o configurar una cuenta con contactos que puedes sincronizar en el teléfono"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear tú mismo un contacto nuevo"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"No tienes ningún contacto para mostrar. (Si has agregado una cuenta, la sincronización de contactos puede demorar pocos minutos)."\n\n"Para agregar contactos, presiona "<font fgcolor="#ffffffff"><b>"Menú"</b></font>" y toca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para agregar y configurar una cuenta con contactos que puedes sincronizar en el teléfono"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Mostrar opciones"</b></font>" para cambiar los contactos que sean visibles"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear tú mismo un contacto nuevo"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"No tienes ningún favorito."\n\n"Para agregar un contacto a tu lista de favoritos:"\n\n" "<li>"toca la pestaña "<b>"Contactos"</b>" "\n</li>" "\n<li>"toca el contacto que deseas agregar a tus favoritos"\n</li>" "\n<li>"toca el asterisco situado junto al nombre del contacto"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Seleccionar grupos para sincronizar"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Todos los contactos"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Todos los contactos"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Marcado con asterisco"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Teléfonos"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Usar teclado de tonos del teléfono"</string>
@@ -176,84 +232,191 @@
<string name="returnCall" msgid="8171961914203617813">"Regresar llamada"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> mins <xliff:g id="SECONDS">%s</xliff:g> s"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Llamado con frecuencia"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Agregar contacto"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Agregar contacto"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"¿Deseas agregar \"<xliff:g id="EMAIL">%s</xliff:g>\" a los contactos?"</string>
- <!-- no translation found for description_image_button_one (1740638037139856139) -->
- <skip />
- <!-- no translation found for description_image_button_two (5882638439003731308) -->
- <skip />
- <!-- no translation found for description_image_button_three (8709731759376015180) -->
- <skip />
- <!-- no translation found for description_image_button_four (3530239685642246130) -->
- <skip />
- <!-- no translation found for description_image_button_five (1182465427501188413) -->
- <skip />
- <!-- no translation found for description_image_button_six (2093656269261415475) -->
- <skip />
- <!-- no translation found for description_image_button_seven (2450357020447676481) -->
- <skip />
- <!-- no translation found for description_image_button_eight (6969435115163287801) -->
- <skip />
- <!-- no translation found for description_image_button_nine (7857248695662558323) -->
- <skip />
- <!-- no translation found for description_image_button_star (3365919907520767866) -->
- <skip />
- <!-- no translation found for description_image_button_zero (4133108949401820710) -->
- <skip />
- <!-- no translation found for description_image_button_pound (3039765597595889230) -->
- <skip />
- <string name="no_sdcard_title" msgid="6455416795090113715">"No hay tarjeta SD"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"No se ha detectado ninguna tarjeta SD"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Buscando VCard"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Todos"</string>
+ <string name="description_image_button_one" msgid="1740638037139856139">"uno"</string>
+ <string name="description_image_button_two" msgid="5882638439003731308">"dos"</string>
+ <string name="description_image_button_three" msgid="8709731759376015180">"tres"</string>
+ <string name="description_image_button_four" msgid="3530239685642246130">"cuatro"</string>
+ <string name="description_image_button_five" msgid="1182465427501188413">"cinco"</string>
+ <string name="description_image_button_six" msgid="2093656269261415475">"seis"</string>
+ <string name="description_image_button_seven" msgid="2450357020447676481">"siete"</string>
+ <string name="description_image_button_eight" msgid="6969435115163287801">"ocho"</string>
+ <string name="description_image_button_nine" msgid="7857248695662558323">"nueve"</string>
+ <string name="description_image_button_star" msgid="3365919907520767866">"asterisco"</string>
+ <string name="description_image_button_zero" msgid="4133108949401820710">"cero"</string>
+ <string name="description_image_button_pound" msgid="3039765597595889230">"libra"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"No hay tarjeta SD"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"No se ha detectado ninguna tarjeta SD"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Buscando vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"¿De dónde quieres importar contactos?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"Tarjeta SIM"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"Tarjeta SD"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importar todos los archivos de VCard"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Importar un archivo de VCard"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Buscando datos VCard en VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"No se ha podido explorar la Tarjeta SD"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"No se ha podido explorar la Tarjeta SD"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importar de la tarjeta SIM"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importar de la tarjeta SD"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Exportar a la tarjeta SD"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importar un archivo de vCard"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importar múltiples archivos de vCard"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importar todos los archivos de vCard"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Buscando datos de vCard en la tarjeta SD"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"No se ha podido explorar la tarjeta SD"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"No se ha podido explorar la tarjeta SD. (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Error de E/S"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"No se ha podido analizar VCard"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"No se ha encontrado un archivo de VCard en la Tarjeta SD"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"No se ha encontrado ninguna entrada válida de VCard para tu selección"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Seleccionar archivo de VCard"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Seleccionar un archivo de VCard para importar"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Leyendo VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Leyendo archivo(s) de VCard"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Importando datos VCard"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"No se han podido leer los datos VCard"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"No se han podido leer los datos VCard"\n"Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"No se ha podido analizar vCard debido a un motivo inesperado"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"No se ha podido analizar vCard aunque el formato parece válido, ya que la implementación actual no lo admite"</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"No se ha encontrado un archivo de vCard en la Tarjeta SD."</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"No se ha encontrado ninguna entrada válida de vCard para tu selección"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"No se pudieron importar uno o más archivos (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Error desconocido"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Seleccionar archivo de vCard"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Selecciona un archivo de vCard para importar"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"Segmento <xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Leyendo vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Leyendo archivo(s) de vCard"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Importando datos de vCard"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"No se han podido leer los datos de vCard"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"No se ha podido leer vCard."\n"Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contactos"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> archivos"</string>
- <!-- no translation found for export_contact_list (3165097742175874384) -->
- <skip />
- <!-- no translation found for confirm_export_title (1693047909433122854) -->
- <skip />
- <!-- no translation found for confirm_export_message (63482084706768079) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_title (1455264422455075858) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_message (1426451081541603512) -->
- <skip />
- <!-- no translation found for fail_reason_too_many_vcard (5416992255233341607) -->
- <skip />
- <!-- no translation found for fail_reason_too_long_filename (7105223965196949065) -->
- <skip />
- <!-- no translation found for fail_reason_cannot_open_destination_dir (1739293936432987758) -->
- <skip />
- <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
- <skip />
- <!-- no translation found for exporting_contact_list_message (5640326540405486055) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_initialize_exporter (4943708332700987376) -->
- <skip />
- <!-- no translation found for fail_reason_error_occurred_during_export (2151165129433831202) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_open_file (4013520943128739511) -->
- <skip />
- <!-- no translation found for exporting_contact_list_progress (560522409559101193) -->
- <skip />
- <!-- no translation found for search_settings_description (2675223022992445813) -->
- <skip />
+ <string name="export_all_contacts" msgid="2873892623335194071">"Todos los contactos"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Contactos guardados localmente"</string>
+ <string name="export_contact_list" msgid="3165097742175874384">"Exportar contactos"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Confirmar exportación"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"¿Estás seguro de que deseas exportar tu lista de contactos a \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\"?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"No se han podido exportar los datos de contacto"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"No se han podido exportar los datos de contacto."\n"Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"No hay ningún contacto exportable"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Demasiados archivos de vCard en la tarjeta SD"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"El nombre de archivo requerido es demasiado largo (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"No se ha podido abrir o crear el directorio de destino \"<xliff:g id="DIR_NAME">%s</xliff:g>\""</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportando datos de contacto"</string>
+ <string name="exporting_contact_list_message" msgid="5640326540405486055">"Exportando datos de contacto a \"<xliff:g id="FILE_NAME">%s</xliff:g>\""</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"No se ha podido inicializar el exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Se produjo un error durante la exportación: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"No se ha podido obtener información de la base de datos"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"No hay ningún contacto exportable. Puedes elegir datos no exportables"</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"El redactor de vCard no se ha inicializado correctamente"</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"No se pudo abrir \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contactos"</string>
+ <string name="search_settings_description" msgid="2675223022992445813">"Nombres de tus contactos"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Agregar pausa de 2 segundos"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Agregar espera"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Marcar"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Llamar con"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Texto con"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Recuerda esta opción"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"No se encontró una aplicación para manejar esta acción."</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Recuerda esta opción."</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Desconocido"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Cuentas"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importar/Exportar"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importar/Exportar contactos"</string>
+ <string name="menu_share" msgid="943789700636542260">"Compartir"</string>
+ <string name="share_via" msgid="563121028023030093">"Compartir un contacto a través de"</string>
+ <string name="share_error" msgid="4374508848981697170">"Este contacto no se puede compartir."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nombre"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Apodo"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organización"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Sitio web"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Evento"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"H"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"Lun."</string>
+ <string name="type_short_work" msgid="4925330752504537861">"Mié."</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"Oct."</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Este contacto es de sólo lectura"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Más"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Nombre principal"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Crear contacto según la cuenta"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Eliminar grupo de sincronización"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Agregar grupo de sincronización"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Más grupos…"</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Todos los otros contactos"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Todos los contactos"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Al suprimir \"<xliff:g id="GROUP">%s</xliff:g>\" de sincronización también se suprimirá cualquier contacto no agrupado de la sincronización."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Sólo telefónicamente (no sincronizado)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Mostrar el nombre"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Llamar a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Llamar al hogar"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Llamar al celular"</string>
+ <string name="call_work" msgid="5328785911463744028">"Llamar al trabajo"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Llamar al fax del trabajo"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Llamar al fax personal"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Llamar a localizador"</string>
+ <string name="call_other" msgid="5605584621798108205">"Llamar a otro"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Llamar a devolución de llamada"</string>
+ <string name="call_car" msgid="3280537320306436445">"Llamar al auto"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Llamar empresa principal"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Llamar a ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Llamada principal"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Llamar a otro fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Llamar a la radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Llamar a télex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Llamar a TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Llamar al celular del trabajo"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Llamar al localizador del trabajo"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Llamar a <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Llamar a MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Texto <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Enviar texto al hogar"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Enviar texto a celular"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Enviar texto al trabajo"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Enviar texto a fax laboral"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Enviar texto a fax personal"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Enviar texto a localizador"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Enviar texto a otro"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Enviar texto a devolución de llamada"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Enviar texto a auto"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Enviar texto a empresa principal"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"ISDN de texto"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Texto principal"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Enviar texto a otro fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Enviar texto a radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Enviar texto a télex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Enviar texto a TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Enviar texto al celular del trabajo"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Enviar texto a localizador del trabajo"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Enviar texto a <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Enviar texto MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"Correo electrónico personal"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Correo electrónico celular"</string>
+ <string name="email_work" msgid="2807430017302722689">"Correo electrónico laboral"</string>
+ <string name="email_other" msgid="8093933498541795832">"Correo electrónico otro"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Correo electrónico <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Correo electrónico"</string>
+ <string name="map_home" msgid="1243547733423343982">"Ver dirección principal"</string>
+ <string name="map_work" msgid="1360474076921878088">"Ver dirección laboral"</string>
+ <string name="map_other" msgid="5560707927535653892">"Ver otra dirección"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Ver <xliff:g id="CUSTOM">%s</xliff:g> dirección"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chat mediante AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chat mediante Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chat mediante Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chat mediante Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chat mediante QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chat mediante Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chat mediante ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chat mediante Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Dirección postal"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Apartado postal"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Barrio"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Ciudad"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Estado"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Código POSTAL"</string>
+ <string name="postal_country" msgid="7638264508416368690">"País"</string>
+ <string name="name_given" msgid="1687286314106019813">"Nombre de pila"</string>
+ <string name="name_family" msgid="3416695586119999058">"Nombre familiar"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Prefijo del nombre"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Segundo nombre"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Sufijo del nombre"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Nombre de pila fonético"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Segundo nombre fonético"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Nombre familiar fonético"</string>
+ <string name="split_label" msgid="8262112659919449087">"Dividir"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Transformar a estos datos en el contacto propio."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"De <xliff:g id="SOURCE">%1$s</xliff:g> la cuenta: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> contacto"</string>
+ <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Usar esta foto"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"La información de <xliff:g id="SOURCE">%1$s</xliff:g> contactos no se puede editar en este dispositivo."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"No hay información adicional para este contacto."</string>
</resources>
diff --git a/res/values-es/config.xml b/res/values-es/config.xml
deleted file mode 100644
index 07b3c7e..0000000
--- a/res/values-es/config.xml
+++ /dev/null
@@ -1,28 +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">
- <!-- no translation found for config_export_vcard_type (9145748078116159716) -->
- <skip />
- <string name="config_export_dir" msgid="222182743639478636">"/sdcard"</string>
- <!-- no translation found for config_export_file_prefix (3022868431158658122) -->
- <skip />
- <!-- no translation found for config_export_file_suffix (16505844221142195) -->
- <skip />
- <string name="config_export_file_extension" msgid="1758878818611339161">"vcf"</string>
- <!-- no translation found for config_export_extensions_to_consider (5095044502091950623) -->
- <skip />
-</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 4da3c5e..d929f9d 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Contactos"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Llamadas"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Teléfono"</string>
<string name="shortcutContact" msgid="749243779392912958">"Contacto"</string>
- <string name="shortcutDialContact" msgid="7165340343023469996">"Llamada directa"</string>
- <string name="shortcutMessageContact" msgid="3025782962770298900">"Mensaje directo"</string>
+ <string name="shortcutDialContact" msgid="746622101599186779">"Llamada directa"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Mensaje directo"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"Elegir un acceso directo para el contacto"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"Elegir un número para la llamada"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Elegir un número para el mensaje"</string>
@@ -40,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Mostrar código de barras"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Editar contacto"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Eliminar contacto"</string>
- <string name="menu_call" msgid="7359207953236681606">"Llamar"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Enviar SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Llamar al contacto"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Enviar un mensaje de texto al contacto"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Enviar mensaje de correo electrónico"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Dirección en mapa"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Convertir en número predeterminado"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Establecer como dirección de correo electrónico predeterminada"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Dividir"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Desagrupar contacto"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Contactos divididos"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Dividir contacto"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"¿Estás seguro de que quieres dividir este contacto único en varios contactos (uno para cada conjunto de información que se añadió a él)?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Agrupar"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Mostrar fuentes"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Ocultar fuentes"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Agrupar contacto"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Agrupar contactos"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Selecciona el nombre del contacto que quieras agrupar con <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Mostrar todos los contactos"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Contactos sugeridos"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Todos los contactos"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Contactos agrupados"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Opciones"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Opciones"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Suprimir"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"No puedes eliminar contactos de las cuentas de solo lectura, pero puedes ocultarlos en las listas de contactos."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Este contacto contiene información de varias cuentas. La información de las cuentas de solo lectura se ocultará en las listas de contactos, pero no se eliminará."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Si se elimina este contacto, se eliminará la información de varias cuentas."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"El contacto se eliminará."</string>
<string name="menu_done" msgid="796017761764190697">"Listo"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Volver"</string>
@@ -55,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Pronunciación"</string>
<string name="label_notes" msgid="8337354953278341042">"Notas"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Tono"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Grupos"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Editar grupos"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Nombre y apellido"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Transcripción fonética del nombre"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
@@ -64,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Número de teléfono"</string>
<string name="ghostData_email" msgid="6184537075551565919">"Dirección de correo electrónico"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Dirección postal"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Mostrar grupo"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Ese contacto no existe."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Crear contacto nuevo"</string>
<string name="selectLabel" msgid="4255424123394910733">"Seleccionar etiqueta"</string>
@@ -80,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"No hay ninguna imagen disponible en el teléfono."</string>
<string name="attachToContact" msgid="8820530304406066714">"Icono de contacto"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Nombre de etiqueta personalizada"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Mostrar grupo"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Opciones de visualización"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Opciones de visualización"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Editar grupos de sincronización"</string>
<string name="importFromSim" msgid="8383900146531125319">"Importar contactos"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Enviar llamadas directamente como mensajes de voz"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Las llamadas se envían directamente al buzón de voz."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Predeterminado"</string>
<string name="addPicture" msgid="1594679312161537678">"Añadir icono"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Cambiar icono"</string>
<string name="removePicture" msgid="3041230993155966350">"Eliminar icono"</string>
<string name="noContacts" msgid="8579310973261953559">"No hay ningún contacto."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"No se ha encontrado ningún contacto coincidente."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"No hay ningún contacto con número de teléfono."</string>
<string name="noFavorites" msgid="812766386743315815">"No hay ningún favorito."</string>
<string name="select_group_title" msgid="7955698611959835612">"Grupos"</string>
<string name="groupEmpty" msgid="6661950109828194595">"El grupo \"<xliff:g id="GROUPNAME">%s</xliff:g>\" está vacío."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Todos los contactos"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Solo contactos con teléfono"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Mostrar solo contactos con números de teléfono"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Seleccionar contactos para mostrar"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> contactos"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> contactos, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> con teléfonos"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Sincronizar todos los contactos"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Mis contactos"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Mis contactos"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Contactos con números de teléfono"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Destacados en Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Guardando contacto…"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Guardando opciones de visualización…"</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Se ha creado el contacto."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"El contacto se ha guardado."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Se ha producido un error al guardar los cambios del contacto."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Marcar número"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Números de teléfono"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Enviar SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Enviar un mensaje de texto"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Enviar mensaje de correo electrónico"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"Direcciones de correo electrónico"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Enviar mensaje instantáneo"</string>
@@ -110,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Dirección en mapa"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Direcciones postales"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organizaciones"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Grupos"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Otra información"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Otras opciones"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Más"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Mostrando un contacto con número de teléfono"</item>
+ <item quantity="other" msgid="6133262880804110289">"Mostrando <xliff:g id="COUNT">%d</xliff:g> contactos con números de teléfono"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"No hay ningún contacto visible con número de teléfono."</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Mostrando un contacto"</item>
+ <item quantity="other" msgid="2865867557378939630">"Mostrando <xliff:g id="COUNT">%d</xliff:g> contactos"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"No hay contactos visibles."</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"Se ha encontrado un contacto."</item>
+ <item quantity="other" msgid="7752927996850263152">"Se han encontrado <xliff:g id="COUNT">%d</xliff:g> contactos."</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"No se ha encontrado el contacto."</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Sociedad"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contactos"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Llamar"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Teléfono"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Registro"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Todos los contactos"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Contactos destacados"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Contactos con números de teléfono"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Enviar mensaje SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Enviar un mensaje de texto"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Llamar a <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Editar número antes de llamar"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Añadir a contactos"</string>
@@ -128,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Borrar registro de llamadas"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"El registro de llamadas está vacío."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Buzón de voz"</string>
<string name="unknown" msgid="740067747858270469">"Desconocidos"</string>
<string name="private_num" msgid="6374339738119166953">"Número privado"</string>
@@ -137,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Cargando desde tarjeta SIM…"</string>
<string name="simContacts_title" msgid="27341688347689769">"Contactos de tarjeta SIM"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Sincroniza tus contactos de Google"</font>" "\n"Después de sincronizarlos con tu teléfono, podrás acceder a tus contactos desde cualquier lugar."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"No tienes ningún contacto."\n\n"Si quieres añadir alguno, pulsa la tecla "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" y selecciona:"\n\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para añadir un contacto manualmente"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar contactos"</b></font>" para añadirlos desde tu tarjeta SIM"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"No tienes ningún contacto."\n\n"Si quieres añadir alguno, pulsa la tecla de menú"<font fgcolor="#ffffffff"><b></b></font>" y selecciona:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Editar grupos de sincronización"</b></font>" para añadirlos desde una cuenta de Google nueva o ya existente"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para añadir un contacto manualmente"\n</li>\n<li><font fgcolor="#ffffffff"><b>"Importar contactos"</b></font>" para añadirlos desde la tarjeta SIM"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"No tienes ningún contacto que mostrar."\n\n"Para añadir contactos, pulsa "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" y toca en:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con los contactos que puedes sincronizar en el teléfono,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar."</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"No tienes ningún contacto que mostrar. (Si acabas de añadir una cuenta, es posible que la sincronización de contactos tarde algunos minutos)."\n\n"Para añadir contactos, pulsa "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" y toca en:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con contactos que puedes sincronizar en el teléfono,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opciones de visualización"</b></font>" para modificar los contactos visibles,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar."</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"No tienes ningún contacto que mostrar."\n\n"Para añadir contactos, pulsa "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" y toca en:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con los contactos que puedes sincronizar en el teléfono,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar."</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"No tienes ningún contacto que mostrar. (Si acabas de añadir una cuenta, es posible que la sincronización de contactos tarde algunos minutos)."\n\n"Para añadir contactos, pulsa "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" y toca en:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Cuentas"</b></font>" para añadir o configurar una cuenta con contactos que puedes sincronizar en el teléfono,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opciones de visualización"</b></font>" para modificar los contactos visibles,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacto nuevo"</b></font>" para crear un nuevo contacto,"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/exportar."</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"No tienes favoritos."\n\n"Para añadir un contacto a tu lista de favoritos, sigue estos pasos:"\n\n" "<li>"Toca en la pestaña "<b>"Contactos"</b>"."\n</li>" "\n<li>"Selecciona el contacto que quieras añadir a tus favoritos."\n</li>" "\n<li>"Toca la estrella situada junto al nombre del contacto."\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Seleccionar grupos para la sincronización"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Todos los contactos"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Todos los contactos"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Destacados"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Teléfonos"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Usar teclado táctil"</string>
@@ -171,8 +232,9 @@
<string name="returnCall" msgid="8171961914203617813">"Devolver llamada"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> min. y <xliff:g id="SECONDS">%s</xliff:g> seg."</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Más llamados"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Añadir contacto"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Añadir contacto"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"¿Deseas añadir \"<xliff:g id="EMAIL">%s</xliff:g>\" a Contactos?"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Todo"</string>
<string name="description_image_button_one" msgid="1740638037139856139">"uno"</string>
<string name="description_image_button_two" msgid="5882638439003731308">"dos"</string>
<string name="description_image_button_three" msgid="8709731759376015180">"tres"</string>
@@ -185,43 +247,176 @@
<string name="description_image_button_star" msgid="3365919907520767866">"estrella"</string>
<string name="description_image_button_zero" msgid="4133108949401820710">"cero"</string>
<string name="description_image_button_pound" msgid="3039765597595889230">"libra"</string>
- <string name="no_sdcard_title" msgid="6455416795090113715">"Falta la tarjeta SD"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"No se ha detectado ninguna tarjeta SD."</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Buscando vCard"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Falta la tarjeta SD."</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"No se ha detectado ninguna tarjeta SD."</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Buscando vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"¿De dónde quieres importar contactos?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"Tarjeta SIM"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"Tarjeta SD"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importar todos los archivos de vCard"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Importar un archivo de vCard"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Buscando datos de vCard en vCard..."</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Error al buscar en tarjeta SD"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Error al buscar en tarjeta SD"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importar contactos desde la tarjeta SIM"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importar contactos desde la tarjeta SD"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Exportar contactos a la tarjeta SD"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importar un archivo de vCard"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importar varios archivos de vCard"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importar todos los archivos de vCard"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Buscando datos de vCard en la tarjeta SD"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Error al buscar en la tarjeta SD"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Error al buscar en la tarjeta SD (motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Error de E/S"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Error al analizar vCard"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"No se ha encontrado ningún archivo de vCard en la tarjeta SD."</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"No se ha encontrado ninguna entrada de vCard válida para la selección realizada."</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Seleccionar archivo de vCard"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Selecciona un archivo de vCard para la operación de importación."</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Leyendo vCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Leyendo archivos de vCard..."</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Importando datos de vCard..."</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Error al leer datos de vCard"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"No ha sido posible leer los datos de vCard."\n"Motivo del error: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"No se ha podido analizar el archivo de vCard debido a un error inesperado."</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"No se ha podido analizar el archivo de vCard (a pesar de que su formato parece ser válido) porque no es compatible con la implementación actual."</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"No se ha encontrado ningún archivo de vCard en la tarjeta SD."</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"No se ha encontrado ninguna entrada de vCard válida para la selección realizada."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"No ha sido posible importar uno o varios archivos (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Error desconocido"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Seleccionar archivo de vCard"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Selecciona un archivo de vCard para la operación de importación."</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Leyendo vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Leyendo archivos de vCard"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Importando datos de vCard"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Error al leer datos de vCard"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Se ha producido un error al leer los datos de vCard."\n"Motivo del error: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contactos"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> archivos"</string>
+ <string name="export_all_contacts" msgid="2873892623335194071">"Todos los contactos"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Contactos almacenados de forma local"</string>
<string name="export_contact_list" msgid="3165097742175874384">"Exportar contactos"</string>
- <string name="confirm_export_title" msgid="1693047909433122854">"Confirmación de exportación"</string>
- <string name="confirm_export_message" msgid="63482084706768079">"¿Confirmas que deseas exportar tu lista de contactos a \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\"?"</string>
- <string name="exporting_contact_failed_title" msgid="1455264422455075858">"Error al exportar datos de contacto"</string>
- <string name="exporting_contact_failed_message" msgid="1426451081541603512">"Se ha producido un error al exportar los datos del contacto."\n"Motivo del error: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
- <string name="fail_reason_too_many_vcard" msgid="5416992255233341607">"Hay demasiados datos de vCard en la tarjeta SD."</string>
- <string name="fail_reason_too_long_filename" msgid="7105223965196949065">"Es necesario un nombre de archivo demasiado largo (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Confirmar la exportación"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"¿Estás seguro de que quieres exportar tu lista de contactos a \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\"?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Error al exportar los datos del contacto"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Se ha producido un error al exportar los datos del contacto."\n"Motivo del error: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"No hay contactos que exportar."</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Hay demasiados archivos de vCard en la tarjeta SD."</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"El nombre de archivo necesario es demasiado largo (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
<string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"No se puede abrir o crear el directorio de destino \"<xliff:g id="DIR_NAME">%s</xliff:g>\"."</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportando datos de contacto"</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"Exportando datos de contacto a \"<xliff:g id="FILE_NAME">%s</xliff:g>\"..."</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"No se ha podido inicializar el exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Se ha producido un error durante la exportación: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Error al obtener información de la base de datos"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"No hay contactos que exportar. Puedes seleccionar datos no exportables."</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"El redactor de vCard no se ha inicializado correctamente."</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"No se ha podido abrir el archivo \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contactos"</string>
<string name="search_settings_description" msgid="2675223022992445813">"Nombres de tus contactos"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Añadir pausa de dos segundos"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Añadir espera"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Llamar"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Llamar a través de"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Enviar un mensaje de texto a través de"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Recordar esta opción"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"No se ha encontrado ninguna aplicación que pueda realizar esta acción."</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Recordar esta opción"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Desconocido"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Cuentas"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importar/exportar"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importar/exportar contactos"</string>
+ <string name="menu_share" msgid="943789700636542260">"Compartir"</string>
+ <string name="share_via" msgid="563121028023030093">"Compartir contacto a través de"</string>
+ <string name="share_error" msgid="4374508848981697170">"Este contacto no se puede compartir."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nombre"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Seudónimo"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organización"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Sitio web"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Evento"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"H"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"W"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"O"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Este contacto se encuentra en modo de solo lectura."</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Más"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Nombre principal"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Crear contacto en la cuenta"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Eliminar grupo de sincronización"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Añadir grupo de sincronización"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Más grupos…"</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Todos los demás contactos"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Todos los contactos"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Si eliminas \"<xliff:g id="GROUP">%s</xliff:g>\" de la sincronización, también se eliminarán todos los contactos no agrupados."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Solo en el teléfono (no sincronizado)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Nombre de presentación"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Llamar a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Llamar a casa"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Llamar al móvil"</string>
+ <string name="call_work" msgid="5328785911463744028">"Llamar al trabajo"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Llamar al fax del trabajo"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Llamar a fax de casa"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Llamar a buscapersonas"</string>
+ <string name="call_other" msgid="5605584621798108205">"Llamar a otro"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Llamar a un número de devolución de llamada"</string>
+ <string name="call_car" msgid="3280537320306436445">"Llamar al coche"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Llamar al teléfono principal de la empresa"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Llamar a RDSI"</string>
+ <string name="call_main" msgid="6082900571803441339">"Llamar al teléfono principal"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Llamar a otro fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Llamar a la radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Llamar al télex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Llamar a TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Llamar al móvil del trabajo"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Llamar al buscapersonas del trabajo"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Llamar a <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Llamar a MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Enviar un mensaje de texto a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Enviar un mensaje de texto a casa"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Enviar SMS a móvil"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Enviar SMS a trabajo"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Enviar un mensaje de texto al fax del trabajo"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Enviar un mensaje de texto al fax de casa"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Enviar un mensaje de texto al buscapersonas"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Enviar un mensaje de texto a otro"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Enviar un mensaje de texto a un número de devolución de llamada"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Enviar un mensaje de texto al coche"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Enviar un mensaje de texto al teléfono principal de la empresa"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Enviar un mensaje de texto a RDSI"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Enviar un mensaje de texto al número de teléfono principal"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Enviar un mensaje de texto a otro fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Enviar un mensaje de texto a la radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Enviar un mensaje de texto al télex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Enviar un mensaje de texto a TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Enviar un mensaje de texto al móvil del trabajo"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Enviar un mensaje de texto al buscapersonas del trabajo"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Enviar un mensaje de texto a <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Enviar un mensaje de texto a MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"Enviar email a casa"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Enviar email al móvil"</string>
+ <string name="email_work" msgid="2807430017302722689">"Enviar email a trabajo"</string>
+ <string name="email_other" msgid="8093933498541795832">"Enviar email a otro"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Correo electrónico <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Correo electrónico"</string>
+ <string name="map_home" msgid="1243547733423343982">"Ver dirección de casa"</string>
+ <string name="map_work" msgid="1360474076921878088">"Ver dirección del trabajo"</string>
+ <string name="map_other" msgid="5560707927535653892">"Ver otras direcciones"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Ver dirección de <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chatear con AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chatear con Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chatear con Yahoo!"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chatear con Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chatear con QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chatear con Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chatear con ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chatear con Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Calle"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Apartado postal"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Vecindario"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Ciudad"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Provincia/Estado"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Código postal"</string>
+ <string name="postal_country" msgid="7638264508416368690">"País"</string>
+ <string name="name_given" msgid="1687286314106019813">"Nombre de pila"</string>
+ <string name="name_family" msgid="3416695586119999058">"Apellidos"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Prefijo del nombre"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Segundo nombre"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Sufijo del nombre"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Nombre de pila fonético"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Segundo nombre fonético"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Apellido fonético"</string>
+ <string name="split_label" msgid="8262112659919449087">"Desagrupar"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Asocia estos datos a su contacto correspondiente."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"De la cuenta <xliff:g id="SOURCE">%1$s</xliff:g>: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"Contacto de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Utilizar esta foto"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"No se puede editar la información del contacto de <xliff:g id="SOURCE">%1$s</xliff:g> en este dispositivo."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"No hay información adicional para este contacto."</string>
</resources>
diff --git a/res/values-fr/config.xml b/res/values-fr/config.xml
deleted file mode 100644
index 07b3c7e..0000000
--- a/res/values-fr/config.xml
+++ /dev/null
@@ -1,28 +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">
- <!-- no translation found for config_export_vcard_type (9145748078116159716) -->
- <skip />
- <string name="config_export_dir" msgid="222182743639478636">"/sdcard"</string>
- <!-- no translation found for config_export_file_prefix (3022868431158658122) -->
- <skip />
- <!-- no translation found for config_export_file_suffix (16505844221142195) -->
- <skip />
- <string name="config_export_file_extension" msgid="1758878818611339161">"vcf"</string>
- <!-- no translation found for config_export_extensions_to_consider (5095044502091950623) -->
- <skip />
-</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index e22a29a..7ed90aa 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Contacts"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Appeler"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Téléphone"</string>
<string name="shortcutContact" msgid="749243779392912958">"Contact"</string>
- <string name="shortcutDialContact" msgid="7165340343023469996">"Raccourci appel"</string>
- <string name="shortcutMessageContact" msgid="3025782962770298900">"Raccourci message"</string>
+ <string name="shortcutDialContact" msgid="746622101599186779">"Raccourci appel"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Raccourci message"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"Choisissez un contact pour le raccourci"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"Choisissez le numéro à appeler"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Choisissez le numéro auquel envoyer le message"</string>
@@ -40,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Afficher le code-barres"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Modifier le contact"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Supprimer le contact"</string>
- <string name="menu_call" msgid="7359207953236681606">"Appel"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Envoyer un SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Appeler le contact"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Envoyer un SMS au contact"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Envoyer un e-mail"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Adresse sur un plan"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Numéro téléphone par défaut"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"E-mail par défaut"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Séparer"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Scinder le contact"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Contacts séparés"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Séparer le contact"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Souhaitez-vous vraiment séparer ce contact en plusieurs instances : une pour chaque ensemble d\'informations associé à ce contact ?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Joindre"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Afficher les sources"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Masquer les sources"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Joindre le contact"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Joindre les contacts"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Sélectionnez le contact que vous voulez associer à <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Afficher tous les contacts"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Contacts suggérés"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Tous les contacts"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Contacts joints"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Options"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Options"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Supprimer"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Impossible de supprimer des contacts des comptes en lecture seule, mais vous pouvez les masquer dans la liste des contacts."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Ce contact contient des informations provenant de plusieurs comptes. Vous pouvez masquer dans votre liste de contacts les informations des comptes en lecture seule, mais pas les supprimer."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"La suppression de ce contact entraînera celle d\'informations provenant de plusieurs comptes."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Ce contact sera supprimé."</string>
<string name="menu_done" msgid="796017761764190697">"OK"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Annuler"</string>
@@ -55,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Prononciation phonétique"</string>
<string name="label_notes" msgid="8337354953278341042">"Notes"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Sonnerie"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Groupes"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Modifier les groupes"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Nom et prénom"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Nom phonétique"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Société"</string>
@@ -64,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Numéro téléphone"</string>
<string name="ghostData_email" msgid="6184537075551565919">"Adresse e-mail"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Adresse postale"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Afficher le groupe"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Ce contact n\'existe pas."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Créer un nouveau contact"</string>
<string name="selectLabel" msgid="4255424123394910733">"Sélectionnez un libellé"</string>
@@ -80,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Aucune image disponible sur le téléphone."</string>
<string name="attachToContact" msgid="8820530304406066714">"Icône de contact"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Libellé personnalisé"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Afficher les groupes"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Options d\'affichage"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Options d\'affichage"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Param. sync. groupes"</string>
<string name="importFromSim" msgid="8383900146531125319">"Importer des contacts"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Renvoyer les appels directement vers la messagerie vocale."</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Les appels sont renvoyés directement vers la messagerie vocale."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Par défaut"</string>
<string name="addPicture" msgid="1594679312161537678">"Ajouter une icône"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Changer d\'icône"</string>
<string name="removePicture" msgid="3041230993155966350">"Supprimer l\'icône"</string>
<string name="noContacts" msgid="8579310973261953559">"Aucun contact."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Aucun contact correspondant n\'a été trouvé."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Aucun contact disposant d\'un numéro téléphone."</string>
<string name="noFavorites" msgid="812766386743315815">"Aucun favori."</string>
<string name="select_group_title" msgid="7955698611959835612">"Groupes"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Votre groupe \"<xliff:g id="GROUPNAME">%s</xliff:g>\" est vide."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Tous les contacts"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Uniquement les contacts avec un téléphone"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Afficher uniquement les contacts avec un numéro de téléphone"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Choisissez les contacts à afficher."</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> contacts"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> contacts, dont <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> avec un téléphone"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Synchroniser tous les contacts"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Mes contacts"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Mes contacts"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Contacts avec des n° de téléphone"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Suivis dans Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Enregistrement du contact…"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Enregistrement des options d\'affichage..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Contact créé."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Contact enregistré."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Erreur : impossible d\'enregistrer les modifications du contact"</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Composer le numéro"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Numéros de téléphone"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Envoyer un SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Envoyer un SMS/MMS"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Envoyer un e-mail"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"Adresses e-mail"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Envoyer un message instantané"</string>
@@ -110,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Adresse sur un plan"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Adresses postales"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organisations"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Groupes"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Autres informations"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Autres options"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Plus"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Afficher 1 contact avec son numéro de téléphone"</item>
+ <item quantity="other" msgid="6133262880804110289">"Affichage de <xliff:g id="COUNT">%d</xliff:g> contacts avec numéro de téléphone"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Aucun contact visible avec numéro de téléphone"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Affichage de 1 contact"</item>
+ <item quantity="other" msgid="2865867557378939630">"Affichage de <xliff:g id="COUNT">%d</xliff:g> contacts"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Aucun contact visible"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"1 contact trouvé"</item>
+ <item quantity="other" msgid="7752927996850263152">"<xliff:g id="COUNT">%d</xliff:g> contacts trouvés"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Contact introuvable"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Social"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contacts"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoris"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Appeler"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Tel."</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Appels"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Tous les contacts"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Contacts suivis"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Contacts avec numéro de téléphone"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Envoyer un message SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Envoyer un SMS"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Appeler <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Modifier le numéro avant d\'effectuer l\'appel"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Ajouter aux contacts"</string>
@@ -128,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Effacer tous les appels"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Aucun appel."</string>
<string name="imei" msgid="3045126336951684285">"Code IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Messagerie vocale"</string>
<string name="unknown" msgid="740067747858270469">"Inconnu"</string>
<string name="private_num" msgid="6374339738119166953">"Numéro privée"</string>
@@ -137,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Chargement depuis la carte SIM..."</string>
<string name="simContacts_title" msgid="27341688347689769">"Contacts de carte SIM"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Synchronisez vos contacts Google !"</font>" "\n"Vos contacts seront disponibles, où que vous soyez, dès que vous aurez synchronisé votre téléphone."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Vous n\'avez aucun contact."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" et sélectionnez :"\n\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un nouveau contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer des contacts"</b></font>" pour ajouter des contacts à partir de votre carte SIM."\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Vous n\'avez aucun contact."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" et sélectionnez :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Param. sync. groupes"</b></font>" pour ajouter un contact à partir d\'un nouveau compte Google ou d\'un compte existant ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un nouveau contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer des contacts"</b></font>" pour ajouter des contacts à partir de votre carte SIM."\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Vous n\'avez aucun contact à afficher."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" et sélectionnez :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte dont vous pourrez synchroniser les contacts sur le téléphone ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter."</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Vous n\'avez aucun contact à afficher (si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes)."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" et sélectionnez :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte comportant des contacts que vous pourrez synchroniser sur le téléphone ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Options d\'affichage"</b></font>" pour modifier le paramètre de visibilité des contacts ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer une entrée ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter."</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Vous n\'avez aucun contact à afficher."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" et sélectionnez :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte dont vous pourrez synchroniser les contacts sur le téléphone ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter."</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Vous n\'avez aucun contact à afficher (si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes)."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" et sélectionnez :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte comportant des contacts que vous pourrez synchroniser sur le téléphone ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Options d\'affichage"</b></font>" pour modifier le paramètre de visibilité des contacts ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer une entrée ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter."</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Vous ne disposez d\'aucun favoris."\n\n"Pour ajouter un contact à la liste de favoris :"\n\n" "<li>"Appuyez sur l\'onglet "<b>"Contacts"</b>"."\n</li>" "\n<li>"Appuyez sur le contact à ajouter à vos favoris."\n</li>" "\n<li>"Appuyez sur l\'étoile en regard du nom du contact."\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Sélectionner les groupes à synchroniser"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Tous les contacts"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Tous les contacts"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Suivis"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Téléphones"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Utiliser le clavier DTMF"</string>
@@ -171,8 +232,9 @@
<string name="returnCall" msgid="8171961914203617813">"Rappeler"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> mn <xliff:g id="SECONDS">%s</xliff:g> s"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Fréquemment appelés"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Ajouter un contact"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Ajouter un contact"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Ajouter \"<xliff:g id="EMAIL">%s</xliff:g>\" aux contacts ?"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Tout"</string>
<string name="description_image_button_one" msgid="1740638037139856139">"un"</string>
<string name="description_image_button_two" msgid="5882638439003731308">"deux"</string>
<string name="description_image_button_three" msgid="8709731759376015180">"trois"</string>
@@ -185,43 +247,176 @@
<string name="description_image_button_star" msgid="3365919907520767866">"étoile"</string>
<string name="description_image_button_zero" msgid="4133108949401820710">"zéro"</string>
<string name="description_image_button_pound" msgid="3039765597595889230">"dièse"</string>
- <string name="no_sdcard_title" msgid="6455416795090113715">"Carte SD introuvable"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Aucune carte SD n\'a été détectée."</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Recherche des données VCard"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Aucune carte SD trouvée"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Aucune carte SD n\'a été détectée."</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Recherche des données VCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"À partir de quel support souhaitez-vous importer les contacts ?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"Carte SIM"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"Carte SD"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importer tous les fichiers VCard"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Importer un fichier VCard"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Recherche de données VCard sur la VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Échec de l\'analyse de la carte SD"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Échec de l\'analyse de la carte SD"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importer à partir de la carte SIM"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importer à partir de la carte SD"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Exporter vers la carte SD"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importer un fichier vCard"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importer plusieurs fichiers vCard"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importer tous les fichiers vCard"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Recherche de données VCard sur la carte SD"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Échec de l\'analyse de la carte SD"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Échec de l\'analyse de la carte SD (Raison : \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Erreur d\'E/S"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Échec de l\'analyse des données VCard"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Aucun fichier VCard n\'a été trouvé sur la carte SD."</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Aucune entrée VCard valide n\'a été trouvée pour votre sélection."</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Sélectionner un fichier VCard"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Sélectionnez un fichier VCard à importer."</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Lecture des données VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Lecture des fichiers VCard"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Importation des données VCard"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Échec de la lecture des données VCard"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"Échec de la lecture des données VCard"\n"Cause : \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Échec de l\'analyse des données VCard pour une raison inattendue"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Échec de l\'analyse des données VCard. Le format semble valide, mais l\'implémentation actuelle ne le prend pas en charge."</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Aucun fichier VCard n\'a été trouvé sur la carte SD."</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Aucune entrée VCard valide n\'a été trouvée pour votre sélection."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Échec de l\'importation d\'un ou de plusieurs fichiers (%s)"</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Erreur inconnue"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Sélectionner un fichier VCard"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Sélectionnez un fichier VCard à importer."</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Lecture des données VCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Lecture des fichiers VCard"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Importation des données VCard"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Échec de la lecture des données VCard"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Impossible de lire les données VCard."\n"Cause : \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> sur <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contacts"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> sur <xliff:g id="TOTAL_NUMBER">%s</xliff:g> fichiers"</string>
+ <string name="export_all_contacts" msgid="2873892623335194071">"Tous les contacts"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Contacts enregistrés localement"</string>
<string name="export_contact_list" msgid="3165097742175874384">"Exporter les contacts"</string>
- <string name="confirm_export_title" msgid="1693047909433122854">"Confirmation de l\'exportation"</string>
- <string name="confirm_export_message" msgid="63482084706768079">"Votre liste de contacts va être exportée vers \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\". Voulez-vous continuer ?"</string>
- <string name="exporting_contact_failed_title" msgid="1455264422455075858">"Échec de l\'exportation des données des contacts"</string>
- <string name="exporting_contact_failed_message" msgid="1426451081541603512">"Échec de l\'exportation des données des contacts"\n"Cause : \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
- <string name="fail_reason_too_many_vcard" msgid="5416992255233341607">"La carte SD contient trop de données VCard."</string>
- <string name="fail_reason_too_long_filename" msgid="7105223965196949065">"Nom de fichier trop long (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Confirmer l\'exportation"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Voulez-vous vraiment exporter la liste de contacts vers \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\" ?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Échec lors de l\'exportation des données du contact"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Échec lors de l\'exportation des données du contact."\n"Motif : \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Aucun contact exportable"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"La carte SD contient trop de fichiers VCard."</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Le nom de fichier requis est trop long (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
<string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Impossible d\'ouvrir ou de créer le répertoire de destination \"<xliff:g id="DIR_NAME">%s</xliff:g>\"."</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportation des données des contacts"</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"Exportation des données des contacts vers \"<xliff:g id="FILE_NAME">%s</xliff:g>\""</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Échec de l\'initialisation du module d\'exportation : \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Une erreur s\'est produite lors de l\'exportation : \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Impossible d\'obtenir les informations concernant la base de données"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Aucun contact exportable. Vous pouvez choisir des données non exportables."</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"Le système de composition vCard n\'est pas correctement initialisé."</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Impossible d\'ouvrir \"<xliff:g id="FILE_NAME">%s</xliff:g>\" : <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> sur <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contacts"</string>
<string name="search_settings_description" msgid="2675223022992445813">"Noms de vos contacts"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Ajouter une pause de 2 s"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Ajouter Attendre"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Composer"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Appeler via"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Envoyer un SMS via"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Mémoriser ce choix"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Aucune application pour gérer cette action"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Mémoriser ce choix"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Inconnu"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Comptes"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importer/Exporter"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importer/Exporter les contacts"</string>
+ <string name="menu_share" msgid="943789700636542260">"Partager"</string>
+ <string name="share_via" msgid="563121028023030093">"Partager contact via"</string>
+ <string name="share_error" msgid="4374508848981697170">"Ce contact ne peut pas être partagé."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nom"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Pseudo"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Site Web"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Événement"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"D"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"B"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"T"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"A"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Ce contact est en lecture seule."</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Plus"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Nom principal"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Créer un contact sous le compte"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Supprimer le groupe de synchronisation"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Ajouter groupe de synchronisation"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Autres groupes..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Tous les autres contacts"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Tous les contacts"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Le retrait du groupe \"<xliff:g id="GROUP">%s</xliff:g>\" de la synchronisation entraîne également la suppression de tous les contacts non groupés de la synchronisation."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Téléphone uniquement (sans synchronisation)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Nom affiché"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Appeler <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Appeler domicile"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Appeler le mobile"</string>
+ <string name="call_work" msgid="5328785911463744028">"Appeler bureau"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Composer télécopie (bureau)"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Composer fax (domicile)"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Appeler téléavertisseur"</string>
+ <string name="call_other" msgid="5605584621798108205">"Appeler autre"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Appeler le numéro de rappel"</string>
+ <string name="call_car" msgid="3280537320306436445">"Appeler voiture"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Appeler société (principal)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Appeler le numéro RNIS"</string>
+ <string name="call_main" msgid="6082900571803441339">"Appeler le numéro principal"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Composer numéro autre fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Appeler par signal radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Appeler par télex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Appeler TTY/TTD (malentendants)"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Appeler sur le mobile professionnel"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Appeler sur le téléavertisseur professionnel"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Appeler <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Appeler MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Envoyer un SMS à <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Envoyer un SMS au domicile"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Envoyer un SMS vers mobile"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Envoyer un SMS au bureau"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Envoyer un SMS vers télécopie (bureau)"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Envoyer un SMS vers télécopie (domicile)"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Envoyer un SMS vers téléavertisseur"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Envoyer un SMS à autre"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Envoyer un SMS au numéro de rappel"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Envoyer un SMS vers voiture"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Envoyer un SMS à société (principal)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Envoyer un SMS vers numéro RNIS"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Envoyer un SMS au numéro principal"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Envoyer un SMS sur autre numéro de fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Envoyer un SMS vers radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Envoyer un SMS par télex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Envoyer SMS vers numéro TTY/TTD (malentendants)"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Envoyer un SMS sur le mobile professionnel"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Envoyer un SMS vers téléavertisseur (bureau)"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Envoyer un message texte à <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Envoyer un MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"Envoyer un e-mail au domicile"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Envoyer un e-mail sur le mobile"</string>
+ <string name="email_work" msgid="2807430017302722689">"Envoyer un e-mail au bureau"</string>
+ <string name="email_other" msgid="8093933498541795832">"Envoyer un e-mail à autre adresse"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Envoyer un e-mail à <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Envoyer un e-mail"</string>
+ <string name="map_home" msgid="1243547733423343982">"Afficher l\'adresse personnelle"</string>
+ <string name="map_work" msgid="1360474076921878088">"Afficher l\'adresse professionnelle"</string>
+ <string name="map_other" msgid="5560707927535653892">"Afficher autre adresse"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Afficher adresse <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chatter via AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chatter via Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chatter via Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chatter via Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chatter via QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chatter via Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chatter via ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chatter via Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Rue"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Boîte postale"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Voisinage"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Ville"</string>
+ <string name="postal_region" msgid="6045263193478437672">"État"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Code postal"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Pays"</string>
+ <string name="name_given" msgid="1687286314106019813">"Prénom"</string>
+ <string name="name_family" msgid="3416695586119999058">"Nom de famille"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Préfixe du nom"</string>
+ <string name="name_middle" msgid="8467433655992690326">"2e prénom"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Suffixe du nom"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Phonétique du prénom"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Phonétique 2e prénom"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Phonétique du nom de famille"</string>
+ <string name="split_label" msgid="8262112659919449087">"Scinder"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Créez un contact avec ces données."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Du compte <xliff:g id="SOURCE">%1$s</xliff:g> : <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"Contact <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Utiliser cette photo"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"Vous ne pouvez pas modifier les informations du contact <xliff:g id="SOURCE">%1$s</xliff:g> sur cet appareil."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Aucune autre information pour ce contact"</string>
</resources>
diff --git a/res/values-it/config.xml b/res/values-it/config.xml
deleted file mode 100644
index ccc13dd..0000000
--- a/res/values-it/config.xml
+++ /dev/null
@@ -1,28 +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">
- <!-- no translation found for config_export_vcard_type (9145748078116159716) -->
- <skip />
- <string name="config_export_dir" msgid="222182743639478636">"/schedasd"</string>
- <!-- no translation found for config_export_file_prefix (3022868431158658122) -->
- <skip />
- <!-- no translation found for config_export_file_suffix (16505844221142195) -->
- <skip />
- <string name="config_export_file_extension" msgid="1758878818611339161">"vcf"</string>
- <!-- no translation found for config_export_extensions_to_consider (5095044502091950623) -->
- <skip />
-</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 45a2395..75ecd6a 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Contatti"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Telefono"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefono"</string>
<string name="shortcutContact" msgid="749243779392912958">"Contatto"</string>
- <string name="shortcutDialContact" msgid="7165340343023469996">"Composizione diretta"</string>
- <string name="shortcutMessageContact" msgid="3025782962770298900">"Messaggio diretto"</string>
+ <string name="shortcutDialContact" msgid="746622101599186779">"Composizione diretta"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Messaggio diretto"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"Scegli una scorciatoia contatto"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"Scegli un numero da chiamare"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Scegli un numero a cui inviare il messaggio"</string>
@@ -40,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Mostra codice a barre"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Modifica contatto"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Elimina contatto"</string>
- <string name="menu_call" msgid="7359207953236681606">"Chiama"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Invia SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Chiama contatto"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Invia testo a n. contatto"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Invia email"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Indirizzo su mappa"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Rendi numero predefinito"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Rendi ind. email predefinito"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Separa"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Dividi contatto"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Contatti separati"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Separa contatto"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Separare questo contatto singolo in più contatti, uno per ogni serie di informazioni di contatto unita in precedenza?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Unisci"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Mostra origini"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Nascondi origini"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Unisci contatto"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Unisci contatti"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Seleziona il contatto che desideri unire a <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Mostra tutti i contatti"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Contatti suggeriti"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Tutti i contatti"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Contatti uniti"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Opzioni"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Opzioni"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Elimina"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Non puoi eliminare contatti di account di sola lettura, ma puoi nasconderli nei tuoi elenchi di contatti."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Il contatto contiene informazioni da più account. Le informazioni provenienti da account di sola lettura verranno nascoste nei tuoi elenchi di contatti, non eliminate."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"L\'eliminazione di questo contatto causerà l\'eliminazione di informazioni da più account."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Il contatto verrà eliminato."</string>
<string name="menu_done" msgid="796017761764190697">"Salva"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Annulla"</string>
@@ -55,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonetica"</string>
<string name="label_notes" msgid="8337354953278341042">"Note"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Suoneria"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Gruppi"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Modifica gruppi"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Nome e cognome"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Nome fonetico"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Società"</string>
@@ -64,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Numero di telefono"</string>
<string name="ghostData_email" msgid="6184537075551565919">"Indirizzo email"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Indirizzo postale"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Visualizza gruppo"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Il contatto non esiste."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Crea nuovo contatto"</string>
<string name="selectLabel" msgid="4255424123394910733">"Seleziona etichetta"</string>
@@ -80,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Nessuna foto disponibile."</string>
<string name="attachToContact" msgid="8820530304406066714">"Icona del contatto"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Nome etichetta personalizzata"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Visualizza gruppo"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Opzioni di visualizzazione"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Opzioni di visualizzazione"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Modifica sincr. gruppi"</string>
<string name="importFromSim" msgid="8383900146531125319">"Importa contatti"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Inoltra chiamate direttamente alla segreteria"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Chiamate inoltrate direttamente alla segreteria."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Predefinita"</string>
<string name="addPicture" msgid="1594679312161537678">"Aggiungi icona"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Cambia icona"</string>
<string name="removePicture" msgid="3041230993155966350">"Rimuovi icona"</string>
<string name="noContacts" msgid="8579310973261953559">"Nessun contatto."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Nessun contatto corrispondente trovato."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Nessun contatto con numeri di telefono."</string>
<string name="noFavorites" msgid="812766386743315815">"Nessun preferito."</string>
<string name="select_group_title" msgid="7955698611959835612">"Gruppi"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Il gruppo \"<xliff:g id="GROUPNAME">%s</xliff:g>\" è vuoto."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Tutti i contatti"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Solo contatti con numeri di telefono"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Visualizza solo i contatti con numeri di telefono"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Scegli i contatti da visualizzare"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> contatti"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> contatti, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> con numeri di telefono"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Sincronizza tutti i contatti"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"I miei contatti"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"I miei contatti"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Contatti con numeri di telefono"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Speciali in Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Salvataggio contatto in corso..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Salvataggio opzioni di visualizzazione in corso..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Contatto creato."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Contatto salvato."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Errore, impossibile salvare le modifiche ai contatti."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Componi numero"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Numeri di telefono"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Invia SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Invia testo"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Invia email"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"Indirizzi email"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Invia messagio chat"</string>
@@ -110,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Indirizzo su mappa"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Indirizzi postali"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organizzazioni"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Gruppi"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Altre informazioni"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Altre opzioni"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Altro"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"1 contatto con numero di telefono visualizzato"</item>
+ <item quantity="other" msgid="6133262880804110289">"<xliff:g id="COUNT">%d</xliff:g> contatti con numeri di telefono visualizzati"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Nessun contatto con numeri di telefono visibile"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"1 contatto visualizzato"</item>
+ <item quantity="other" msgid="2865867557378939630">"<xliff:g id="COUNT">%d</xliff:g> contatti visualizzati"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Nessun contatto visibile"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"1 contatto trovato"</item>
+ <item quantity="other" msgid="7752927996850263152">"<xliff:g id="COUNT">%d</xliff:g> contatti trovati"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Contatto non trovato"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Sociale"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contatti"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Preferiti"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Telefono"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefono"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Chiamate"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Tutti i contatti"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Contatti speciali"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Contatti con numeri di telefono"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Invia SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Invia messaggio di testo"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Chiama <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Modifica prima di chiamare"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Aggiungi a contatti"</string>
@@ -128,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Cancella registro chiamate"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Il registro chiamate è vuoto."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Segreteria"</string>
<string name="unknown" msgid="740067747858270469">"Sconosciuto"</string>
<string name="private_num" msgid="6374339738119166953">"Numero privato"</string>
@@ -137,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Caricamento da SIM..."</string>
<string name="simContacts_title" msgid="27341688347689769">"Contatti SIM"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Sincronizza i tuoi contatti Google."</font>" "\n"Dopo la sincronizzazione con il telefono, i tuoi contatti saranno sempre a tua disposizione."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Non è presente alcun contatto."\n\n"Per aggiungere contatti, premi "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e seleziona:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Nuovo contatto"</b></font>" per creare un contatto nuovo"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importa contatti"</b></font>" per aggiungere contatti dalla SIM"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Non è presente alcun contatto."\n\n"Per aggiungere contatti, premi "<font fgcolor="#ffffffff"><b>" Menu"</b></font>" e seleziona:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Modifica sincr. gruppi"</b></font>" per aggiungere contatti da un account Google nuovo o esistente"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nuovo contatto"</b></font>" per creare un contatto nuovo"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importa contatti"</b></font>" per aggiungere contatti dalla SIM"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Non sono presenti contatti da visualizzare."\n\n"Per aggiungere contatti, premi "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e tocca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Account"</b></font>" per aggiungere o configurare un account con contatti sincronizzabili con il telefono"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nuovo contatto"</b></font>" per creare da zero un nuovo contatto"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importa/esporta"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Non sono presenti contatti da visualizzare (se hai appena aggiunto un account, la sincronizzazione dei contatti potrebbe richiedere alcuni minuti)."\n\n"Per aggiungere contatti, premi "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e tocca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Account"</b></font>" per aggiungere o configurare un account con contatti sincronizzabili con il telefono"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opzioni di visualizzazione"</b></font>" per modificare i contatti visibili"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nuovo contatto"</b></font>" per creare da zero un nuovo contatto"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importa/esporta"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Non sono presenti contatti da visualizzare."\n\n"Per aggiungere contatti, premi "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e tocca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Account"</b></font>" per aggiungere o configurare un account con contatti sincronizzabili con il telefono"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nuovo contatto"</b></font>" per creare da zero un nuovo contatto"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importa/esporta"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Non sono presenti contatti da visualizzare (se hai appena aggiunto un account, la sincronizzazione dei contatti potrebbe richiedere alcuni minuti)."\n\n"Per aggiungere contatti, premi "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e tocca:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Account"</b></font>" per aggiungere o configurare un account con contatti sincronizzabili con il telefono"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opzioni di visualizzazione"</b></font>" per modificare i contatti visibili"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nuovo contatto"</b></font>" per creare da zero un nuovo contatto"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importa/esporta"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Non sono presenti preferiti."\n\n"Per aggiungere un contatto al tuo elenco di preferiti:"\n\n" "<li>"Tocca la scheda "<b>"Contatti."</b>\n</li>" "\n<li>"Tocca il contatto da aggiungere ai preferiti."\n</li>" "\n<li>"Tocca la stella accanto al nome del contatto."\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Seleziona i gruppi da sincronizzare"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Tutti i contatti"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Tutti i contatti"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Speciali"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Telefoni"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Usa tastierino per selezione a toni"</string>
@@ -171,8 +232,9 @@
<string name="returnCall" msgid="8171961914203617813">"Chiama numero"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> min. <xliff:g id="SECONDS">%s</xliff:g> sec."</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Numeri più chiamati"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Aggiungi contatto"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Aggiungi contatto"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Aggiungere \"<xliff:g id="EMAIL">%s</xliff:g>\" ai contatti?"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Tutti"</string>
<string name="description_image_button_one" msgid="1740638037139856139">"uno"</string>
<string name="description_image_button_two" msgid="5882638439003731308">"due"</string>
<string name="description_image_button_three" msgid="8709731759376015180">"tre"</string>
@@ -185,43 +247,176 @@
<string name="description_image_button_star" msgid="3365919907520767866">"stella"</string>
<string name="description_image_button_zero" msgid="4133108949401820710">"zero"</string>
<string name="description_image_button_pound" msgid="3039765597595889230">"sterlina"</string>
- <string name="no_sdcard_title" msgid="6455416795090113715">"Nessuna scheda SD"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Nessuna scheda SD rilevata"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Ricerca VCard"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Nessuna scheda SD"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Nessuna scheda SD rilevata"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Ricerca vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Da dove desideri importare i contatti?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"Scheda SIM"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"Scheda SD"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importa tutti i file VCard"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Importa un file VCard"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Ricerca dati VCard su VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Analisi scheda SD non riuscita"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Analisi scheda SD non riuscita"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importa da scheda SIM"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importa da scheda SD"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Esporta su scheda SD"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importa un file vCard"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importa più file vCard"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importa tutti i file vCard"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Ricerca dati vCard su scheda SD"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Analisi scheda SD non riuscita"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Analisi scheda SD non riuscita (motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Errore I/O"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Analisi VCard non riuscita"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Nessun file VCard trovato sulla scheda SD"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Nessuna voce VCard valida trovata per la tua selezione"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Seleziona file VCard"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Seleziona un file VCard da importare"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Lettura VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Lettura file VCard"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Importazione dati VCard"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Lettura dati VCard non riuscita"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"Impossibile leggere i dati VCard"\n"Motivo dell\'errore: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Impossibile analizzare la vCard per motivi imprevisti"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Impossibile analizzare la vCard nonostante sembri avere un formato valido perché l\'implementazione corrente non la supporta"</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Nessun file vCard trovato sulla scheda SD"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Nessuna voce vCard valida trovata per la tua selezione"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Impossibile importare uno o più file (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Errore sconosciuto"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Seleziona file vCard"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Seleziona un file vCard da importare"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Lettura vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Lettura file vCard"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Importazione dati vCard"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Lettura dati vCard non riuscita"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Impossibile leggere la vCard."\n"Motivo dell\'errore: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> contatti su <xliff:g id="TOTAL_NUMBER">%s</xliff:g>"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> file su <xliff:g id="TOTAL_NUMBER">%s</xliff:g>"</string>
+ <string name="export_all_contacts" msgid="2873892623335194071">"Tutti i contatti"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Contatti memorizzati localmente"</string>
<string name="export_contact_list" msgid="3165097742175874384">"Esporta contatti"</string>
- <string name="confirm_export_title" msgid="1693047909433122854">"Conferma dell\'esportazione"</string>
- <string name="confirm_export_message" msgid="63482084706768079">"Esportare l\'elenco contatti in \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\"?"</string>
- <string name="exporting_contact_failed_title" msgid="1455264422455075858">"Esportazione dati di contatto non riuscita"</string>
- <string name="exporting_contact_failed_message" msgid="1426451081541603512">"Impossibile esportare i dati di contatto"\n"Motivo dell\'errore: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
- <string name="fail_reason_too_many_vcard" msgid="5416992255233341607">"Troppi dati VCard sulla scheda SD"</string>
- <string name="fail_reason_too_long_filename" msgid="7105223965196949065">"Nome del file troppo lungo (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Conferma esportazione"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Esportare l\'elenco di contatti in \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\"?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Esportazione dati contatti non riuscita"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Esportazione dati contatti non riuscita."\n"Motivo dell\'errore: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Nessun contatto esportabile"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Troppi dati vCard sulla scheda SD"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Il nome file richiesto è troppo lungo (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
<string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Impossibile aprire o creare la directory di destinazione \"<xliff:g id="DIR_NAME">%s</xliff:g>\""</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"Esportazione dati di contatto"</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"Esportazione dati di contatto in \"<xliff:g id="FILE_NAME">%s</xliff:g>\""</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Impossibile inizializzare l\'utilità di esportazione: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Si è verificato un errore durante l\'esportazione: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Recupero informazioni database non riuscito"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Nessun contatto esportabile. Potresti scegliere dati non esportabili"</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"Il compositore di vCard non è correttamente inizializzato"</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Impossibile aprire \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> contatti su <xliff:g id="TOTAL_NUMBER">%s</xliff:g>"</string>
<string name="search_settings_description" msgid="2675223022992445813">"I nomi dei tuoi contatti"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Aggiungi pausa 2 sec"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Aggiungi attesa"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Componi"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Chiama utilizzando"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Invia SMS utilizzando"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Memorizza questa scelta"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Nessuna applicazione trovata in grado di gestire questa azione"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Memorizza questa scelta"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Sconosciuto"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Account"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importa/esporta"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importa/esporta contatti"</string>
+ <string name="menu_share" msgid="943789700636542260">"Condividi"</string>
+ <string name="share_via" msgid="563121028023030093">"Condividi contatto tramite"</string>
+ <string name="share_error" msgid="4374508848981697170">"Impossibile condividere il contatto."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nome"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Nickname"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizzazione"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Sito web"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Evento"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"H"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"W"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"O"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Questo contatto è di sola lettura"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Altro"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Nome principale"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Crea contatto sotto account"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Rimuovi gruppo sinc."</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Aggiungi gruppo sinc."</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Altri gruppi..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Tutti gli altri contatti"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Tutti i contatti"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Se rimuovi \"<xliff:g id="GROUP">%s</xliff:g>\" dalla sincronizzazione, verranno rimossi anche tutti i contatti separati."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Solo su telefono (non sincronizzato)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Nome visualizzato"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Chiama n. <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Chiama n. casa"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Chiama n. cellulare"</string>
+ <string name="call_work" msgid="5328785911463744028">"Chiama n. ufficio"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Chiama n. fax ufficio"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Chiama n. fax casa"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Chiama n. cercapersone"</string>
+ <string name="call_other" msgid="5605584621798108205">"Chiama altro"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Chiama n. callback"</string>
+ <string name="call_car" msgid="3280537320306436445">"Chiama n. automobile"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Chiama n. azienda, principale"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Chiama n. ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Chiama n. principale"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Chiama n. altro fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Chiama n. segnale cellulare"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Chiama n. telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Chiama n. TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Chiama n. cellulare ufficio"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Chiama n. cercapersone ufficio"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Chiama <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Chiama n. MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Invia SMS a n. <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Invia SMS a n. casa"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Invia SMS a n. cellulare"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Invia SMS a n. ufficio"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Invia SMS a n. fax ufficio"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Invia SMS a n. fax casa"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Invia SMS a n. cercapersone"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Invia SMS ad altro"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Invia SMS a n. callback"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Invia SMS a n. automobile"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Invia SMS a n. azienda, principale"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Invia SMS a n. ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Invia SMS a n. principale"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Invia SMS a n. altro fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Invia SMS a n. segnale cellulare"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Invia SMS a n. telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Invia SMS a n. TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Invia SMS a n. cellulare ufficio"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Invia SMS a n. cercapersone ufficio"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Invia testo a <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Invia SMS a n. MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"Invia email a ind. casa"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Invia email a ind. cellulare"</string>
+ <string name="email_work" msgid="2807430017302722689">"Invia email a ind. ufficio"</string>
+ <string name="email_other" msgid="8093933498541795832">"Invia email ad altro"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Invia email a ind. <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Email"</string>
+ <string name="map_home" msgid="1243547733423343982">"Visualizza indirizzo di casa"</string>
+ <string name="map_work" msgid="1360474076921878088">"Visualizza indirizzo ufficio"</string>
+ <string name="map_other" msgid="5560707927535653892">"Visualizza altro indirizzo"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Visualizza indirizzo <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chatta tramite AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chatta tramite Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chatta tramite Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chatta tramite Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chatta tramite QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chatta tramite Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chatta tramite ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chatta tramite Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chatta"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Indirizzo postale"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Casella postale"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Zona"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Città"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Provincia"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Codice postale"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Paese"</string>
+ <string name="name_given" msgid="1687286314106019813">"Nome fornito"</string>
+ <string name="name_family" msgid="3416695586119999058">"Cognome"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Prefisso nome"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Secondo nome"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Suffisso nome"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Nome fonetico fornito"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Secondo nome fonetico"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Cognome fonetico"</string>
+ <string name="split_label" msgid="8262112659919449087">"Dividi"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Crea un contatto distinto con questi dati."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Da account <xliff:g id="SOURCE">%1$s</xliff:g>: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"Contatto da <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="from_account_format" msgid="687567483928582084">"da <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Utilizza questa foto"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"Informazioni del contatto da <xliff:g id="SOURCE">%1$s</xliff:g> non modificabili su questo dispositivo."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Nessuna informazione aggiuntiva per questo contatto"</string>
</resources>
diff --git a/res/values-ja/config.xml b/res/values-ja/config.xml
deleted file mode 100644
index 07b3c7e..0000000
--- a/res/values-ja/config.xml
+++ /dev/null
@@ -1,28 +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">
- <!-- no translation found for config_export_vcard_type (9145748078116159716) -->
- <skip />
- <string name="config_export_dir" msgid="222182743639478636">"/sdcard"</string>
- <!-- no translation found for config_export_file_prefix (3022868431158658122) -->
- <skip />
- <!-- no translation found for config_export_file_suffix (16505844221142195) -->
- <skip />
- <string name="config_export_file_extension" msgid="1758878818611339161">"vcf"</string>
- <!-- no translation found for config_export_extensions_to_consider (5095044502091950623) -->
- <skip />
-</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 301bc4a..fdb7858 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"連絡先"</string>
- <string name="launcherDialer" msgid="140610573639849799">"電話"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"電話"</string>
<string name="shortcutContact" msgid="749243779392912958">"連絡先"</string>
- <string name="shortcutDialContact" msgid="7165340343023469996">"直接発信"</string>
- <string name="shortcutMessageContact" msgid="3025782962770298900">"直接メッセージを送る"</string>
+ <string name="shortcutDialContact" msgid="746622101599186779">"直接発信"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"直接メッセージを送る"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"連絡先ショートカットを選択"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"発信する番号の選択"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"メッセージを送る番号の選択"</string>
@@ -40,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"バーコードを表示"</string>
<string name="menu_editContact" msgid="3452858480713561396">"連絡先を編集"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"連絡先を削除"</string>
- <string name="menu_call" msgid="7359207953236681606">"発信"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"SMSを送信"</string>
+ <string name="menu_call" msgid="3992595586042260618">"連絡先に発信"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"連絡先にSMS"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"メールを送信"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"地図でみる"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"メインの番号に設定する"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"既定のメールに設定"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"分割"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"連絡先を分割"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"連絡先を分割しました"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"連絡先を分割"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"この連絡先を複数の連絡先に分割してもよろしいですか?統合前の連絡先情報にそれぞれ分割されます。"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"統合"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"ソースを表示"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"ソースを非表示"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"連絡先を統合"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"連絡先の統合"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"<xliff:g id="NAME">%s</xliff:g>と統合する連絡先を選択します。"</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"すべての連絡先を表示"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"連絡先候補"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"すべての連絡先"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"連絡先を結合しました"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"オプション"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"オプション"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"削除"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"読み取り専用アカウントの連絡先は削除できませんが、連絡先リストで非表示にすることができます。"</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"この連絡先には、複数のアカウント情報が含まれています。読み取り専用アカウントの情報を連絡先リストで非表示にすることはできますが、削除はできません。"</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"この連絡先を削除すると、複数のアカウント情報が削除されます。"</string>
<string name="deleteConfirmation" msgid="811706994761610640">"この連絡先を削除します。"</string>
<string name="menu_done" msgid="796017761764190697">"完了"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"キャンセル"</string>
@@ -55,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"読み"</string>
<string name="label_notes" msgid="8337354953278341042">"メモ"</string>
<string name="label_ringtone" msgid="8833166825330686244">"着信音"</string>
+ <string name="label_groups" msgid="7304551384542859026">"グループ"</string>
+ <string name="group_list" msgid="8583361685440161307">"、<xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"グループを編集"</string>
<string name="ghostData_name" msgid="6490954238641157585">"名前"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"よみがな"</string>
<string name="ghostData_company" msgid="5414421120553765775">"会社"</string>
@@ -64,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"電話番号"</string>
<string name="ghostData_email" msgid="6184537075551565919">"メールアドレス"</string>
<string name="ghostData_postal" msgid="652611650594951897">"住所"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"グループを表示"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"この連絡先は削除されました"</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"連絡先を新規登録"</string>
<string name="selectLabel" msgid="4255424123394910733">"選択してください"</string>
@@ -80,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"画像がありません。"</string>
<string name="attachToContact" msgid="8820530304406066714">"連絡先のアイコン"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"新しいラベル名"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"グループを表示"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"表示オプション"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"表示オプション"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"同期する範囲"</string>
<string name="importFromSim" msgid="8383900146531125319">"連絡先をインポート"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"ボイスメールに自動転送する"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"この番号にかけるとボイスメールに転送されます。"</string>
<string name="default_ringtone" msgid="9099988849649827972">"端末既定"</string>
<string name="addPicture" msgid="1594679312161537678">"アイコンを追加"</string>
+ <string name="changePicture" msgid="2943329047610967714">"アイコンを変更"</string>
<string name="removePicture" msgid="3041230993155966350">"アイコンを削除"</string>
<string name="noContacts" msgid="8579310973261953559">"連絡先がありません。"</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"一致する連絡先が見つかりません。"</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"電話番号付きの連絡先はありません。"</string>
<string name="noFavorites" msgid="812766386743315815">"お気に入りなし"</string>
<string name="select_group_title" msgid="7955698611959835612">"グループ"</string>
<string name="groupEmpty" msgid="6661950109828194595">"「<xliff:g id="GROUPNAME">%s</xliff:g>」グループには何も登録されていません。"</string>
<string name="showAllGroups" msgid="5164410117611094297">"すべての連絡先"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"電話番号のある連絡先のみ"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"電話番号のある連絡先のみ表示する"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"表示する連絡先の選択"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g>件の連絡先"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g>件の連絡先、<xliff:g id="COUNTWITHPHONES">%2$d</xliff:g>件電話番号あり"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"全連絡先を同期"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Myコンタクト"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Myコンタクト"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"電話番号のある連絡先"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Androidでスター付きの連絡先"</string>
+ <string name="savingContact" msgid="4075751076741924939">"連絡先を保存しています..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"表示オプションを保存中..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"連絡先を作成しました。"</string>
<string name="contactSavedToast" msgid="7152589189385441091">"連絡先を保存しました。"</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"エラー、連絡先の変更を保存できません。"</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"発信"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"電話番号"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"SMSを送信"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"SMSを送信"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"メールを送信"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"メールアドレス"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"インスタントメッセージを送信"</string>
@@ -110,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"地図でみる"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"住所"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"所属"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"グループ"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"その他の情報"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"その他のオプション"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"開く"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"電話番号のある連絡先1件を表示"</item>
+ <item quantity="other" msgid="6133262880804110289">"電話番号のある連絡先<xliff:g id="COUNT">%d</xliff:g>件を表示"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"表示可能な電話番号付きの連絡先はありません"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"連絡先を1件表示"</item>
+ <item quantity="other" msgid="2865867557378939630">"連絡先を<xliff:g id="COUNT">%d</xliff:g>件表示"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"表示可能な連絡先はありません"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"連絡先が1件あります"</item>
+ <item quantity="other" msgid="7752927996850263152">"連絡先が<xliff:g id="COUNT">%d</xliff:g>件あります"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"連絡先が見つかりません"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"ソーシャル"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"連絡先"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"お気入り"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"電話"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"電話"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"通話履歴"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"すべての連絡先"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"スター付きの連絡先"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"電話番号のある連絡先"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"SMSメッセージを送信"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"SMSを送信"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"<xliff:g id="NAME">%s</xliff:g>に発信"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"発信前に番号を編集"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"連絡先に追加"</string>
@@ -128,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"通話履歴を全件消去"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"通話履歴なし"</string>
<string name="imei" msgid="3045126336951684285">"IMEI(端末識別番号)"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"ボイスメール"</string>
<string name="unknown" msgid="740067747858270469">"通知不可能"</string>
<string name="private_num" msgid="6374339738119166953">"非通知"</string>
@@ -137,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"SIMカードから読み取り中..."</string>
<string name="simContacts_title" msgid="27341688347689769">"SIMカードの連絡先"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Googleアカウントの連絡先同期"</font>" "\n"Googleサービスで使っている連絡先をこの携帯電話でも使えるようになります。"</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"連絡先が登録されていません。"\n\n<font fgcolor="#ffffffff"><b>"MENU"</b></font>"キーを押して登録方法を選択してください:"\n" "\n<li><font fgcolor="#ffffffff"><b>"連絡先を新規登録"</b></font>": 連絡先を入力して新規作成します"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"連絡先をインポート"</b></font>": 連絡先をSIMカードおよびSDカードから取り込みます"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"連絡先が登録されていません。"\n\n<font fgcolor="#ffffffff"><b>"MENU"</b></font>"キーを押して登録方法を選択してください:"\n\n<li><font fgcolor="#ffffffff"><b>"同期する範囲"</b></font>": Googleアカウントから連絡先を読み込んで追加します"\n</li>\n<li><font fgcolor="#ffffffff"><b>"連絡先を新規登録"</b></font>": 連絡先を入力して新規作成します"\n</li>\n<li><font fgcolor="#ffffffff"><b>"連絡先をインポート"</b></font>": 連絡先をSIMカードから取り込みます"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"表示できる連絡先がありません。"\n\n"連絡先を追加するには、まず"<font fgcolor="#ffffffff"><b>"MENU"</b></font>"キーを押し: "\n" "\n<li>"電話との同期が可能な連絡先のアカウントを追加または設定する場合は["<font fgcolor="#ffffffff"><b>"アカウント"</b></font>"]をタップします"\n</li>" "\n<li>"新しい連絡先を一から作成する場合は["<font fgcolor="#ffffffff"><b>"連絡先を新規登録"</b></font>"]をタップします"\n</li>" "\n<li>"["<font fgcolor="#ffffffff"><b>"インポート/エクスポート"</b></font>"]"\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"表示できる連絡先がありません(アカウントを追加した場合は、連絡先が同期されるまでに数分かかることがあります)。"\n\n"連絡先を追加するには、まず"<font fgcolor="#ffffffff"><b>"MENU"</b></font>"キーを押し: "\n" "\n<li>"電話との同期が可能な連絡先のアカウントを追加または設定する場合は["<font fgcolor="#ffffffff"><b>"アカウント"</b></font>"]をタップします"\n</li>" "\n<li>"表示される連絡先を変更するには["<font fgcolor="#ffffffff"><b>"表示オプション"</b></font>"]をタップします"\n</li>" "\n<li>"新しい連絡先を最初から作成する場合は["<font fgcolor="#ffffffff"><b>"連絡先を新規登録"</b></font>"]をタップします"\n</li>" "\n<li>"["<font fgcolor="#ffffffff"><b>"インポート/エクスポート"</b></font>"]"\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"表示できる連絡先がありません。"\n\n"連絡先を追加するには、まず"<font fgcolor="#ffffffff"><b>"MENU"</b></font>"キーを押し: "\n" "\n<li>"電話との同期が可能な連絡先のアカウントを追加または設定する場合は["<font fgcolor="#ffffffff"><b>"アカウント"</b></font>"]をタップします"\n</li>" "\n<li>"新しい連絡先を最初から作成する場合は["<font fgcolor="#ffffffff"><b>"連絡先を新規登録"</b></font>"]をタップします"\n</li>" "\n<li>"["<font fgcolor="#ffffffff"><b>"インポート/エクスポート"</b></font>"]"\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"表示できる連絡先がありません(アカウントを追加した場合は、連絡先が同期されるまでに数分かかることがあります)。"\n\n"連絡先を追加するには、まず"<font fgcolor="#ffffffff"><b>"MENU"</b></font>"キーを押し: "\n" "\n<li>"電話との同期が可能な連絡先のアカウントを追加または設定する場合は["<font fgcolor="#ffffffff"><b>"アカウント"</b></font>"]をタップします"\n</li>" "\n<li>"表示される連絡先を変更するには["<font fgcolor="#ffffffff"><b>"表示オプション"</b></font>"]をタップします"\n</li>" "\n<li>"新しい連絡先を最初から作成する場合は["<font fgcolor="#ffffffff"><b>"連絡先を新規登録"</b></font>"]をタップします"\n</li>" "\n<li>"["<font fgcolor="#ffffffff"><b>"インポート/エクスポート"</b></font>"]"\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"お気に入りはありません。"\n\n"お気に入りのリストに連絡先を追加するには: "\n\n" "<li>"["<b>"連絡先"</b>"]タブをタップします"\n</li>" "\n<li>"お気に入りに追加する連絡先をタップします"\n</li>" "\n<li>"連絡先名の横にあるスターをタップします"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"同期するグループを選択"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"すべての連絡先"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"すべての連絡先"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"スター付き"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"電話"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"プッシュホン式キーパッドを使う"</string>
@@ -171,8 +232,9 @@
<string name="returnCall" msgid="8171961914203617813">"発信"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g>分<xliff:g id="SECONDS">%s</xliff:g>秒"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"よく使う連絡先"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"連絡先を追加"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"連絡先を追加"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"<xliff:g id="EMAIL">%s</xliff:g> を連絡先に追加しますか?"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"すべて"</string>
<string name="description_image_button_one" msgid="1740638037139856139">"1"</string>
<string name="description_image_button_two" msgid="5882638439003731308">"2"</string>
<string name="description_image_button_three" msgid="8709731759376015180">"3"</string>
@@ -185,43 +247,176 @@
<string name="description_image_button_star" msgid="3365919907520767866">"スター"</string>
<string name="description_image_button_zero" msgid="4133108949401820710">"0"</string>
<string name="description_image_button_pound" msgid="3039765597595889230">"ポンド"</string>
- <string name="no_sdcard_title" msgid="6455416795090113715">"SDカードがありません"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"SDカードを検出できませんでした"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"VCardを検索中"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"SDカードがありません"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"SDカードを検出できませんでした"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"vCardを検索中"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"連絡先のインポート元を選択してください"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIMカード"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"SDカード"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"すべてのVCardファイルをインポートする"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"VCardファイルを1つインポートする"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"VCardのVCardデータを検索しています"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"SDカードのスキャン失敗"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"SDカードのスキャンに失敗しました"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"SIMカードからインポート"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"SDカードからインポート"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"SDカードにエクスポート"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"vCardファイルを1つインポート"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"複数のvCardファイルをインポート"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"すべてのvCardファイルをインポート"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"SDカードのvCardデータを検索しています"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"SDカードのスキャンに失敗しました"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"SDカードのスキャンに失敗しました(理由: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"送受信エラー"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"VCardの解析に失敗しました"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"SDカードでVCardファイルが見つかりません"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"選択した内容の有効なVCardエントリが見つかりません"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"VCardファイルの選択"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"インポートするVCardファイルを選択してください"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"VCardを読み取り中"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"VCardファイルを読み取り中"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"VCardデータをインポート中"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"VCardデータの読み取りに失敗しました"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"VCardデータを読み取れませんでした"\n"エラーの理由: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"予期しない理由によりvCardの解析に失敗しました"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"vCardの解析に失敗しました。正しいフォーマットですが、現在サポートされていません。"</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"SDカードでvCardファイルが見つかりません"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"選択した内容の有効なvCardエントリが見つかりません"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"1つ以上のファイルをインポートできませんでした(%s)。"</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"不明なエラー"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"vCardファイルの選択"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"インポートするvCardファイルを選択してください"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"vCardを読み取り中"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"vCardファイルを読み取り中"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"vCardデータをインポート中"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"vCardデータの読み取りに失敗しました"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"vCardを読み取れません。"\n"理由: 「<xliff:g id="FAIL_REASON">%s</xliff:g>」"</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>件の連絡先"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>件のファイル"</string>
+ <string name="export_all_contacts" msgid="2873892623335194071">"すべての連絡先"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"電話だけに保存されている連絡先"</string>
<string name="export_contact_list" msgid="3165097742175874384">"連絡先をエクスポート"</string>
- <string name="confirm_export_title" msgid="1693047909433122854">"エクスポートの確認"</string>
- <string name="confirm_export_message" msgid="63482084706768079">"連絡先を\"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\"にエクスポートしてもよろしいですか?"</string>
- <string name="exporting_contact_failed_title" msgid="1455264422455075858">"連絡先データのエクスポートに失敗しました"</string>
- <string name="exporting_contact_failed_message" msgid="1426451081541603512">"連絡先データのエクスポートに失敗しました"\n"エラーの理由: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
- <string name="fail_reason_too_many_vcard" msgid="5416992255233341607">"SDカードのVCardデータが多すぎます"</string>
- <string name="fail_reason_too_long_filename" msgid="7105223965196949065">"ファイル名(「<xliff:g id="FILENAME">%s</xliff:g>」)が長すぎます"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"エクスポートの確認"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"連絡先リストを「<xliff:g id="VCARD_FILENAME">%s</xliff:g>」にエクスポートしますか?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"連絡先データのエクスポートに失敗しました"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"連絡先データのエクスポートに失敗しました。"\n"理由: 「<xliff:g id="FAIL_REASON">%s</xliff:g>」"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"エクスポートできる連絡先がありません"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"SDカードのvCardファイルが多すぎます"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"指定したファイル名が長すぎます(「<xliff:g id="FILENAME">%s</xliff:g>」)"</string>
<string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"ディレクトリ\"<xliff:g id="DIR_NAME">%s</xliff:g>\"を開けません"</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"連絡先データのエクスポート"</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"連絡先データを\"<xliff:g id="FILE_NAME">%s</xliff:g>\"にエクスポートしています"</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"エクスポータを初期化できませんでした: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"エクスポート中にエラーが発生しました: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"データベース情報の取得に失敗しました"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"エクスポートできる連絡先がありません。エクスポートできないデータを選択している可能性があります。"</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"vCardコンポーザーが正しく初期化されていません"</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\"を開けませんでした: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>件のファイル"</string>
<string name="search_settings_description" msgid="2675223022992445813">"連絡先の名前"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"2秒間の停止を追加"</string>
+ <string name="add_wait" msgid="3360818652790319634">"着信を追加"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"発信"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"使用している発信"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"使用しているSMS"</string>
+ <string name="make_primary" msgid="5829291915305113983">"この選択を保存"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"この操作を行うアプリケーションが見つかりません"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"この選択を保存"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"不明"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"アカウント"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"インポート/エクスポート"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"連絡先のインポート/エクスポート"</string>
+ <string name="menu_share" msgid="943789700636542260">"共有"</string>
+ <string name="share_via" msgid="563121028023030093">"連絡先の共有ツール"</string>
+ <string name="share_error" msgid="4374508848981697170">"この連絡先は共有できません。"</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"名前"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"ニックネーム"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"所属"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"ウェブサイト"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"予定"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"自宅"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"携帯"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"勤務先"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"ポケベル"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"その他"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"この連絡先は読み取り専用です"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"その他"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"メインの名前"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"アカウントに連絡先を作成"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"同期グループを削除"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"同期グループに追加"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"他のグループ..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"その他の連絡先"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"すべての連絡先"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"「<xliff:g id="GROUP">%s</xliff:g>」を同期から除外すると、グループに含まれない連絡先もすべて同期から除外されます。"</string>
+ <string name="account_phone" msgid="4025734638492419713">"電話のみ(非同期)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"表示名"</string>
+ <string name="call_custom" msgid="7756571794763171802">"<xliff:g id="CUSTOM">%s</xliff:g>に発信"</string>
+ <string name="call_home" msgid="1990519474420545392">"自宅に発信"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"携帯電話に発信"</string>
+ <string name="call_work" msgid="5328785911463744028">"勤務先に発信"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"勤務先FAXに発信"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"自宅のFAXに発信"</string>
+ <string name="call_pager" msgid="9003902812293983281">"ポケベルに発信"</string>
+ <string name="call_other" msgid="5605584621798108205">"その他に発信"</string>
+ <string name="call_callback" msgid="1910165691349426858">"コールバック先に発信"</string>
+ <string name="call_car" msgid="3280537320306436445">"クルマに発信"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"会社代表番号に発信"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"ISDNに発信"</string>
+ <string name="call_main" msgid="6082900571803441339">"電話番号1に発信"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"FAX(その他)に発信"</string>
+ <string name="call_radio" msgid="8296755876398357063">"無線に発信"</string>
+ <string name="call_telex" msgid="2223170774548648114">"テレックスに発信"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"TTY/TDDに発信"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"携帯電話(勤務先)に発信"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"ポケベル(勤務先)に発信"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"<xliff:g id="ASSISTANT">%s</xliff:g>に発信"</string>
+ <string name="call_mms" msgid="6274041545876221437">"MMSに発信"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"<xliff:g id="CUSTOM">%s</xliff:g>にSMS"</string>
+ <string name="sms_home" msgid="7524332261493162995">"自宅にSMS"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"携帯にSMS"</string>
+ <string name="sms_work" msgid="2269624156655267740">"勤務先にSMS"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"勤務先FAXにSMS"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"自宅FAXにSMS"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"ポケベルにSMS"</string>
+ <string name="sms_other" msgid="5131921487474531617">"その他にSMS"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"コールバック先にSMS"</string>
+ <string name="sms_car" msgid="7444227058437359641">"クルマにSMS"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"会社代表番号にSMS"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"ISDNにSMS"</string>
+ <string name="sms_main" msgid="8621625784504541679">"電話番号1にSMS"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"FAX(その他)にSMS"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"無線にSMS"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"テレックスにSMS"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"TTY/TDDにSMS"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"携帯電話(勤務先)にSMS"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"ポケベル(勤務先)にSMS"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"<xliff:g id="ASSISTANT">%s</xliff:g>にSMS"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"MMSにSMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"自宅にメール"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"携帯電話にメール"</string>
+ <string name="email_work" msgid="2807430017302722689">"勤務先にメール"</string>
+ <string name="email_other" msgid="8093933498541795832">"その他にメール"</string>
+ <string name="email_custom" msgid="7548003991586214105">"<xliff:g id="CUSTOM">%s</xliff:g>にメール"</string>
+ <string name="email" msgid="5668400997660065897">"メール"</string>
+ <string name="map_home" msgid="1243547733423343982">"自宅の住所を表示"</string>
+ <string name="map_work" msgid="1360474076921878088">"勤務先の住所を表示"</string>
+ <string name="map_other" msgid="5560707927535653892">"その他の住所を表示"</string>
+ <string name="map_custom" msgid="6184363799976265281">"<xliff:g id="CUSTOM">%s</xliff:g>の住所を表示"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"AIMでチャット"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Windows Liveでチャット"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Yahooでチャット"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Skypeでチャット"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"QQでチャット"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Googleトークでチャット"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"ICQでチャット"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Jabberでチャット"</string>
+ <string name="chat" msgid="9025361898797412245">"チャット"</string>
+ <string name="postal_street" msgid="8133143961580058972">"番地"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"私書箱"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"近所"</string>
+ <string name="postal_city" msgid="6597491300084895548">"市区町村"</string>
+ <string name="postal_region" msgid="6045263193478437672">"都道府県"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"郵便番号"</string>
+ <string name="postal_country" msgid="7638264508416368690">"国"</string>
+ <string name="name_given" msgid="1687286314106019813">"名"</string>
+ <string name="name_family" msgid="3416695586119999058">"姓"</string>
+ <string name="name_prefix" msgid="59756378548779822">"敬称(名前の前)"</string>
+ <string name="name_middle" msgid="8467433655992690326">"ミドルネーム"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"敬称(名前の後)"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"名のフリガナ"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"ミドルネームのフリガナ"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"姓のフリガナ"</string>
+ <string name="split_label" msgid="8262112659919449087">"分割"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"このデータから独自の連絡先を作成します。"</string>
+ <string name="account_name_format" msgid="4421123930035299208">"<xliff:g id="SOURCE">%1$s</xliff:g>アカウント: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g>からの連絡先"</string>
+ <string name="from_account_format" msgid="687567483928582084">"<xliff:g id="SOURCE">%1$s</xliff:g>からの連絡先"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"この写真を使用"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g>からの連絡先情報はこの携帯端末では編集できません。"</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"この連絡先の詳細情報はありません"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index a91f9af..0057e0d 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -16,18 +16,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"주소록"</string>
- <string name="launcherDialer" msgid="140610573639849799">"다이얼러"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"휴대전화"</string>
<string name="shortcutContact" msgid="749243779392912958">"연락처"</string>
- <!-- no translation found for shortcutDialContact (7165340343023469996) -->
- <skip />
- <!-- no translation found for shortcutMessageContact (3025782962770298900) -->
- <skip />
- <!-- no translation found for shortcutActivityTitle (6642877210643565436) -->
- <skip />
- <!-- no translation found for callShortcutActivityTitle (6065749861423648991) -->
- <skip />
- <!-- no translation found for messageShortcutActivityTitle (3084542316620335911) -->
- <skip />
+ <string name="shortcutDialContact" msgid="746622101599186779">"바로 전화 걸기"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"바로 메시지 보내기"</string>
+ <string name="shortcutActivityTitle" msgid="6642877210643565436">"연락처 바로가기 선택"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"통화할 번호 선택"</string>
+ <string name="messageShortcutActivityTitle" msgid="3084542316620335911">"메시지를 보낼 번호 선택"</string>
<string name="starredList" msgid="4817256136413959463">"중요주소록"</string>
<string name="frequentList" msgid="7154768136473953056">"자주 사용하는 연락처"</string>
<string name="strequentList" msgid="5640192862059373511">"즐겨찾기"</string>
@@ -45,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"바코드 표시"</string>
<string name="menu_editContact" msgid="3452858480713561396">"연락처 수정"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"연락처 삭제"</string>
- <string name="menu_call" msgid="7359207953236681606">"통화"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"SMS/MMS 보내기"</string>
+ <string name="menu_call" msgid="3992595586042260618">"연락처로 전화 걸기"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"연락처에 문자 보내기"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"이메일 보내기"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"지도상의 주소"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"기본 번호로 설정"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"기본 이메일로 설정"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"분할"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"연락처 분할"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"연락처가 분할되었습니다."</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"연락처 분할"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"연락처 하나를 여러 주소록으로 분할하시겠습니까? 가입된 연락처 정보 세트마다 하나씩 만드시겠습니까?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"결합"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"소스 표시"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"소스 숨기기"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"연락처 결합"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"연락처 결합"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"<xliff:g id="NAME">%s</xliff:g>와(과) 결합할 연락처를 선택하세요."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"모든 연락처 표시"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"추천 연락처"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"모든 연락처"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"연락처 결합됨"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"옵션"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"옵션"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"삭제"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"읽기 전용 계정의 주소록은 삭제할 수 없지만 주소록 목록에서 숨길 수는 있습니다."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"연락처에 여러 계정의 정보가 들어 있습니다. 읽기 전용 계정의 정보는 주소록 목록에서 숨길 수 있지만 삭제할 수는 없습니다."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"이 연락처를 삭제하면 여러 계정의 정보가 삭제됩니다."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"연락처가 삭제됩니다."</string>
<string name="menu_done" msgid="796017761764190697">"완료"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"되돌리기"</string>
@@ -60,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"소리나는 대로"</string>
<string name="label_notes" msgid="8337354953278341042">"메모"</string>
<string name="label_ringtone" msgid="8833166825330686244">"벨소리"</string>
+ <string name="label_groups" msgid="7304551384542859026">"그룹"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"그룹 수정"</string>
<string name="ghostData_name" msgid="6490954238641157585">"이름"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"이름(소리나는 대로)"</string>
<string name="ghostData_company" msgid="5414421120553765775">"회사"</string>
@@ -69,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"전화번호"</string>
<string name="ghostData_email" msgid="6184537075551565919">"이메일 주소"</string>
<string name="ghostData_postal" msgid="652611650594951897">"주소"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"그룹 표시"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"연락처가 없습니다."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"새 연락처 만들기"</string>
<string name="selectLabel" msgid="4255424123394910733">"라벨 선택"</string>
@@ -85,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"휴대전화에 사진이 없습니다."</string>
<string name="attachToContact" msgid="8820530304406066714">"연락처 아이콘"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"라벨 이름 맞춤 설정"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"그룹 표시"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"표시 옵션"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"표시 옵션"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"동기화 그룹 수정"</string>
<string name="importFromSim" msgid="8383900146531125319">"주소록 가져오기"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"수신전화를 바로 음성메일로 보내기"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"수신전화가 바로 음성메일로 연결됩니다."</string>
<string name="default_ringtone" msgid="9099988849649827972">"기본값"</string>
<string name="addPicture" msgid="1594679312161537678">"아이콘 추가"</string>
+ <string name="changePicture" msgid="2943329047610967714">"변경 아이콘"</string>
<string name="removePicture" msgid="3041230993155966350">"아이콘 삭제"</string>
<string name="noContacts" msgid="8579310973261953559">"주소록이 없습니다."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"일치하는 연락처가 없습니다."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"전화번호가 포함된 주소록이 없습니다."</string>
<string name="noFavorites" msgid="812766386743315815">"즐겨찾기가 없습니다."</string>
<string name="select_group_title" msgid="7955698611959835612">"그룹"</string>
<string name="groupEmpty" msgid="6661950109828194595">"\'<xliff:g id="GROUPNAME">%s</xliff:g>\' 그룹이 비어 있습니다."</string>
<string name="showAllGroups" msgid="5164410117611094297">"모든 주소록"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"전화가 있는 연락처만"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"전화번호가 있는 연락처만 표시"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"표시할 연락처 선택"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"연락처 <xliff:g id="COUNT">%0$d</xliff:g>개"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"연락처 <xliff:g id="COUNT_0">%1$d</xliff:g>개, 전화가 있는 연락처 <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g>개"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"모든 주소록 동기화"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"내 주소록"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"내 주소록"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"전화번호가 포함된 주소록"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Android 중요주소록"</string>
+ <string name="savingContact" msgid="4075751076741924939">"연락처 저장 중..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"표시 옵션 저장 중...."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"연락처를 만들었습니다."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"연락처를 저장했습니다."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"오류가 발생해서 연락처 변경사항을 저장할 수 없습니다."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"전화걸기"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"전화번호"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"SMS/MMS 보내기"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"문자 보내기"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"이메일 보내기"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"이메일 주소"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"채팅 메시지 보내기"</string>
@@ -115,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"지도상의 주소"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"주소"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"조직"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"그룹"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"기타 정보"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"기타 옵션"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"더보기"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"전화번호와 함께 연락처 1개 표시"</item>
+ <item quantity="other" msgid="6133262880804110289">"전화번호가 포함된 주소록 <xliff:g id="COUNT">%d</xliff:g>개 표시"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"전화번호가 포함된, 표시할 수 있는 주소록이 없습니다."</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"연락처 1개 표시"</item>
+ <item quantity="other" msgid="2865867557378939630">"<xliff:g id="COUNT">%d</xliff:g>개 주소록 표시"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"표시할 수 있는 주소록이 없습니다."</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"연락처 1개를 찾았습니다."</item>
+ <item quantity="other" msgid="7752927996850263152">"연락처 <xliff:g id="COUNT">%d</xliff:g>개를 찾았습니다."</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"연락처를 찾을 수 없습니다."</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"소셜"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"주소록"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"즐겨찾기"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"다이얼러"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"휴대전화"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"통화기록"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"모든 주소록"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"중요주소록"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"전화번호가 포함된 주소록"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"SMS 메시지 보내기"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"문자 메시지 보내기"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"통화: <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"통화하기 전에 번호 수정"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"주소록에 추가"</string>
@@ -133,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"통화기록 지우기"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"통화기록이 없습니다."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"음성메일"</string>
<string name="unknown" msgid="740067747858270469">"알 수 없음"</string>
<string name="private_num" msgid="6374339738119166953">"비공개 번호"</string>
@@ -142,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"SIM 카드에서 로딩 중..."</string>
<string name="simContacts_title" msgid="27341688347689769">"SIM 카드 주소록"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Google 주소록 동기화"</font>" "\n"휴대전화에 동기화하면 어디서나 주소록을 사용할 수 있습니다."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"주소록이 없습니다. "\n\n"주소록을 추가하려면 "<font fgcolor="#ffffffff"><b>"메뉴"</b></font>"를 누르고 다음을 선택하세요. "\n" "\n<li><font fgcolor="#ffffffff"><b>"새 연락처"</b></font>" - 새 연락처를 만들려는 경우"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"주소록 가져오기"</b></font>" - SIM 카드에서 주소록을 추가하려는 경우"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"주소록이 없습니다."\n\n"주소록을 추가하려면 "<font fgcolor="#ffffffff"><b>"메뉴"</b></font>"를 누르고 다음을 선택하세요. "\n" "\n<li><font fgcolor="#ffffffff"><b>"동기화 그룹 수정"</b></font>" - 새로운 또는 기존 Google 계정에서 추가하려는 경우"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"새 연락처"</b></font>" - 새 연락처를 만들려는 경우"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"주소록 가져오기"</b></font>" - SIM 카드에서 주소록을 추가하려는 경우"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"표시할 연락처가 없습니다."\n\n"연락처를 추가하려면 "<font fgcolor="#ffffffff"><b>"메뉴"</b></font>"를 누르고 다음을 터치합니다. "\n" "\n<li><font fgcolor="#ffffffff"><b>"계정"</b></font>": 휴대전화에 동기화할 수 있는 연락처가 있는 계정을 구성하거나 추가하려면 터치합니다. "\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"새 연락처"</b></font>": 연락처를 새로 만들려면 터치합니다."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"가져오기/내보내기"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"표시할 연락처가 없습니다. 방금 계정을 추가한 경우 연락처를 동기화하는 데 몇 분 정도 걸릴 수 있습니다."\n\n"연락처를 추가하려면 "<font fgcolor="#ffffffff"><b>"메뉴"</b></font>"를 누르고 다음을 터치합니다. "\n" "\n<li><font fgcolor="#ffffffff"><b>"계정"</b></font>": 휴대전화에 동기화할 수 있는 연락처가 있는 계정을 구성하거나 추가하려면 터치합니다. "\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"표시 옵션"</b></font>": 표시되는 연락처를 변경하려면 터치합니다."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"새 연락처"</b></font>": 연락처를 새로 만들려면 터치합니다. "\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"가져오기/내보내기"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"표시할 연락처가 없습니다"\n\n"연락처를 추가하려면 "<font fgcolor="#ffffffff"><b>"메뉴"</b></font>"를 누르고 다음을 터치합니다. "\n" "\n<li><font fgcolor="#ffffffff"><b>"계정"</b></font>": 휴대전화에 동기화할 수 있는 연락처가 있는 계정을 구성하거나 추가하려는 경우 터치합니다. "\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"새 연락처"</b></font>": 연락처를 새로 만들려면 터치합니다."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"가져오기/내보내기"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"표시할 연락처가 없습니다. 방금 계정을 추가한 경우 연락처를 동기화하는 데 몇 분 정도 걸릴 수 있습니다."\n\n"연락처를 추가하려면 "<font fgcolor="#ffffffff"><b>"메뉴"</b></font>"를 누르고 다음을 터치합니다. "\n" "\n<li><font fgcolor="#ffffffff"><b>"계정"</b></font>": 휴대전화에 동기화할 수 있는 연락처가 있는 계정을 구성하거나 추가하려면 터치합니다. "\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"표시 옵션"</b></font>": 표시되는 연락처를 변경하려면 터치합니다."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"새 연락처"</b></font>": 연락처를 새로 만들려면 터치합니다. "\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"가져오기/내보내기"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"즐겨찾기가 없습니다. "\n\n"즐겨찾기 목록에 연락처를 추가하려면 "\n\n<li><b>"주소록"</b>" 탭을 터치하고"\n</li>" "\n<li>"즐겨찾기에 추가할 연락처를 터치하고"\n</li>" "\n<li>"연락처 이름 옆의 별표를 터치합니다."\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"동기화할 그룹 선택"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"모든 주소록"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"모든 연락처"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"중요 주소록"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"휴대전화"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"터치톤 키패드 사용"</string>
@@ -176,84 +232,191 @@
<string name="returnCall" msgid="8171961914203617813">"회신 통화에 전화걸기"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g>분 <xliff:g id="SECONDS">%s</xliff:g>초"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"자주 통화한 목록"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"연락처 추가"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"연락처 추가"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"\'<xliff:g id="EMAIL">%s</xliff:g>\'을(를) 주소록에 추가하겠습니까?"</string>
- <!-- no translation found for description_image_button_one (1740638037139856139) -->
- <skip />
- <!-- no translation found for description_image_button_two (5882638439003731308) -->
- <skip />
- <!-- no translation found for description_image_button_three (8709731759376015180) -->
- <skip />
- <!-- no translation found for description_image_button_four (3530239685642246130) -->
- <skip />
- <!-- no translation found for description_image_button_five (1182465427501188413) -->
- <skip />
- <!-- no translation found for description_image_button_six (2093656269261415475) -->
- <skip />
- <!-- no translation found for description_image_button_seven (2450357020447676481) -->
- <skip />
- <!-- no translation found for description_image_button_eight (6969435115163287801) -->
- <skip />
- <!-- no translation found for description_image_button_nine (7857248695662558323) -->
- <skip />
- <!-- no translation found for description_image_button_star (3365919907520767866) -->
- <skip />
- <!-- no translation found for description_image_button_zero (4133108949401820710) -->
- <skip />
- <!-- no translation found for description_image_button_pound (3039765597595889230) -->
- <skip />
- <string name="no_sdcard_title" msgid="6455416795090113715">"SD 카드 없음"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"SD 카드가 발견되지 않았습니다."</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"VCard 검색"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"모두"</string>
+ <string name="description_image_button_one" msgid="1740638037139856139">"1"</string>
+ <string name="description_image_button_two" msgid="5882638439003731308">"2"</string>
+ <string name="description_image_button_three" msgid="8709731759376015180">"3"</string>
+ <string name="description_image_button_four" msgid="3530239685642246130">"4"</string>
+ <string name="description_image_button_five" msgid="1182465427501188413">"5"</string>
+ <string name="description_image_button_six" msgid="2093656269261415475">"6"</string>
+ <string name="description_image_button_seven" msgid="2450357020447676481">"7"</string>
+ <string name="description_image_button_eight" msgid="6969435115163287801">"8"</string>
+ <string name="description_image_button_nine" msgid="7857248695662558323">"9"</string>
+ <string name="description_image_button_star" msgid="3365919907520767866">"별"</string>
+ <string name="description_image_button_zero" msgid="4133108949401820710">"0"</string>
+ <string name="description_image_button_pound" msgid="3039765597595889230">"#"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"SD 카드 없음"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"SD 카드가 발견되지 않았습니다."</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"vCard 검색"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"어디에서 주소록을 가져오시겠습니까?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIM 카드"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"SD 카드"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"모든 VCard 파일 가져오기"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"VCard 파일 한 개 가져오기"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"VCard에서 VCard 데이터 검색 중"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"SD 카드 스캔 실패"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"SD 카드 스캔 실패"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM 카드에서 가져오기"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"SD 카드에서 가져오기"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"SD 카드로 내보내기"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"vCard 파일 한 개 가져오기"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"vCard 파일 여러 개 가져오기"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"모든 vCard 파일 가져오기"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"SD 카드의 vCard 데이터 검색"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"SD 카드 스캔 실패"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"SD 카드 스캔 실패(이유: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\')"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O 오류"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"VCard 구문분석에 실패했습니다."</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"SD 카드에 VCard 파일이 없습니다."</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"선택한 항목에 유효한 VCard 주소가 없습니다."</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"VCard 파일 선택"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"가져올 VCard 파일을 선택하세요."</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"VCard 읽는 중"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"VCard 파일 읽는 중"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"VCard 데이터 가져오기"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"VCard 데이터를 읽어오지 못했습니다."</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"VCard 데이터를 읽을 수 없습니다."\n"실패 이유: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\'"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"예기치 못한 이유로 인해 vCard를 구문분석하지 못했습니다."</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"올바른 형식처럼 보이지만 현재 구현 환경에서는 VCard를 지원하지 않기 때문에 VCard 구문 분석에 실패했습니다."</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"SD 카드에 VCard 파일이 없습니다."</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"선택한 항목에 유효한 VCard 항목이 없습니다."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"하나 이상의 파일을 가져오지 못했습니다(%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"알 수 없는 오류"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"vCard 파일 선택"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"가져올 vCard 파일을 선택하세요."</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"vCard 읽는 중"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"vCard 파일 읽는 중"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"vCard 데이터 가져오는 중"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"vCard 데이터를 읽어오지 못했습니다."</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"vCard를 읽지 못했습니다. "\n"실패 이유: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\'"</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"주소록 <xliff:g id="TOTAL_NUMBER">%s</xliff:g>개 중 <xliff:g id="CURRENT_NUMBER">%s</xliff:g>개"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"파일 <xliff:g id="TOTAL_NUMBER">%s</xliff:g>개 중 <xliff:g id="CURRENT_NUMBER">%s</xliff:g>개"</string>
- <!-- no translation found for export_contact_list (3165097742175874384) -->
- <skip />
- <!-- no translation found for confirm_export_title (1693047909433122854) -->
- <skip />
- <!-- no translation found for confirm_export_message (63482084706768079) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_title (1455264422455075858) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_message (1426451081541603512) -->
- <skip />
- <!-- no translation found for fail_reason_too_many_vcard (5416992255233341607) -->
- <skip />
- <!-- no translation found for fail_reason_too_long_filename (7105223965196949065) -->
- <skip />
- <!-- no translation found for fail_reason_cannot_open_destination_dir (1739293936432987758) -->
- <skip />
- <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
- <skip />
- <!-- no translation found for exporting_contact_list_message (5640326540405486055) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_initialize_exporter (4943708332700987376) -->
- <skip />
- <!-- no translation found for fail_reason_error_occurred_during_export (2151165129433831202) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_open_file (4013520943128739511) -->
- <skip />
- <!-- no translation found for exporting_contact_list_progress (560522409559101193) -->
- <skip />
- <!-- no translation found for search_settings_description (2675223022992445813) -->
- <skip />
+ <string name="export_all_contacts" msgid="2873892623335194071">"모든 연락처"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"로컬로 저장된 연락처"</string>
+ <string name="export_contact_list" msgid="3165097742175874384">"연락처 내보내기"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"내보내기 확인"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"\'<xliff:g id="VCARD_FILENAME">%s</xliff:g>\'(으)로 연락처 목록을 내보내시겠습니까?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"연락처 데이터를 내보내지 못했습니다."</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"연락처 데이터를 내보내지 못했습니다."\n"실패 이유: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\'"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"내보낼 수 있는 연락처가 없습니다."</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"SD 카드에 vCard 파일이 너무 많습니다."</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"필수 파일 이름이 너무 깁니다(\'<xliff:g id="FILENAME">%s</xliff:g>\')."</string>
+ <string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"대상 디렉토리(\'<xliff:g id="DIR_NAME">%s</xliff:g>\')를 열거나 만들 수 없습니다."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"연락처 데이터 내보내기"</string>
+ <string name="exporting_contact_list_message" msgid="5640326540405486055">"연락처 데이터를 \'<xliff:g id="FILE_NAME">%s</xliff:g>\'(으)로 내보내는 중"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"내보내기를 초기화하지 못했습니다. \'<xliff:g id="EXACT_REASON">%s</xliff:g>\'"</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"내보내는 중에 오류가 발생했습니다. \'<xliff:g id="EXACT_REASON">%s</xliff:g>\'"</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"데이터베이스 정보를 가져오지 못했습니다."</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"내보낼 수 있는 연락처가 없습니다. 내보낼 수 없는 데이터를 선택할 수 있습니다."</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"vCard 작성기가 바르게 초기화되지 않았습니다."</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"\'<xliff:g id="FILE_NAME">%s</xliff:g>\'을(를) 열 수 없습니다. <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_progress" msgid="560522409559101193">"연락처 <xliff:g id="CURRENT_NUMBER">%s</xliff:g>개(총 <xliff:g id="TOTAL_NUMBER">%s</xliff:g>개) 내보내는 중"</string>
+ <string name="search_settings_description" msgid="2675223022992445813">"연락처 명단"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"2초 간 일시 정지 추가"</string>
+ <string name="add_wait" msgid="3360818652790319634">"대기 시간 추가"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"전화걸기"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"다음을 사용하여 통화:"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"다음을 사용하여 문자 보내기:"</string>
+ <string name="make_primary" msgid="5829291915305113983">"이 선택사항 저장"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"이 작업을 처리하는 응용프로그램을 찾을 수 없습니다."</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"이 선택사항 저장"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"알 수 없음"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"계정"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"가져오기/내보내기"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"연락처 가져오기/내보내기"</string>
+ <string name="menu_share" msgid="943789700636542260">"공유"</string>
+ <string name="share_via" msgid="563121028023030093">"연락처 공유에 사용할 응용프로그램:"</string>
+ <string name="share_error" msgid="4374508848981697170">"연락처를 공유할 수 없습니다."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"이름"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"닉네임"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"조직"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"웹사이트"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"일정"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"H"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"W"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"O"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"연락처가 읽기 전용입니다."</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"더보기"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"기본 이름"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"계정에서 연락처 만들기"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"동기화 그룹 삭제"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"동기화 그룹 추가"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"그룹 더보기..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"다른 모든 연락처"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"모든 연락처"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"\'<xliff:g id="GROUP">%s</xliff:g>\'을(를) 동기화에서 제거하면 그룹화되지 않은 연락처도 동기화에서 제거됩니다."</string>
+ <string name="account_phone" msgid="4025734638492419713">"전화기 전용(동기화되지 않음)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"표시 이름"</string>
+ <string name="call_custom" msgid="7756571794763171802">"<xliff:g id="CUSTOM">%s</xliff:g>(으)로 전화걸기"</string>
+ <string name="call_home" msgid="1990519474420545392">"집으로 전화걸기"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"휴대전화로 전화걸기"</string>
+ <string name="call_work" msgid="5328785911463744028">"직장으로 전화걸기"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"직장 팩스로 전화걸기"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"집 팩스로 전화걸기"</string>
+ <string name="call_pager" msgid="9003902812293983281">"호출기로 전화걸기"</string>
+ <string name="call_other" msgid="5605584621798108205">"기타 연락처로 전화걸기"</string>
+ <string name="call_callback" msgid="1910165691349426858">"콜백 번호로 전화 걸기"</string>
+ <string name="call_car" msgid="3280537320306436445">"카폰으로 전화걸기"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"회사 기본전화로 전화걸기"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"ISDN으로 전화걸기"</string>
+ <string name="call_main" msgid="6082900571803441339">"기본 번호로 전화 걸기"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"다른 팩스로 전화걸기"</string>
+ <string name="call_radio" msgid="8296755876398357063">"무선통신으로 전화걸기"</string>
+ <string name="call_telex" msgid="2223170774548648114">"텔렉스 통화"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"TTY/TDD 통화"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"직장 휴대전화로 전화걸기"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"직장 호출기로 전화 걸기"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"<xliff:g id="ASSISTANT">%s</xliff:g>에게 전화"</string>
+ <string name="call_mms" msgid="6274041545876221437">"MMS로 전화걸기"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"문자(<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="sms_home" msgid="7524332261493162995">"집으로 문자 보내기"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"휴대전화로 문자 보내기"</string>
+ <string name="sms_work" msgid="2269624156655267740">"직장으로 문자 보내기"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"직장 팩스로 문자 보내기"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"집 팩스로 문자 보내기"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"호출기로 문자 보내기"</string>
+ <string name="sms_other" msgid="5131921487474531617">"기타 연락처로 문자 보내기"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"콜백 번호로 문자 보내기"</string>
+ <string name="sms_car" msgid="7444227058437359641">"카폰으로 문자 보내기"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"회사 기본전화로 문자 보내기"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"ISDN에 문자 보내기"</string>
+ <string name="sms_main" msgid="8621625784504541679">"기본 번호로 문자 보내기"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"기타 팩스로 문자 보내기"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"무선통신으로 문자 보내기"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"텔렉스로 문자 보내기"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"TTY/TDD에 문자 보내기"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"직장 휴대전화로 문자 보내기"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"직장 호출기로 문자 보내기"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"<xliff:g id="ASSISTANT">%s</xliff:g>(으)로 문자 보내기"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"MMS로 문자 보내기"</string>
+ <string name="email_home" msgid="8573740658148184279">"집으로 이메일 보내기"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"모바일로 이메일 보내기"</string>
+ <string name="email_work" msgid="2807430017302722689">"직장으로 이메일 보내기"</string>
+ <string name="email_other" msgid="8093933498541795832">"기타 연락처로 이메일 보내기"</string>
+ <string name="email_custom" msgid="7548003991586214105">"이메일(<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="email" msgid="5668400997660065897">"이메일"</string>
+ <string name="map_home" msgid="1243547733423343982">"집 주소 보기"</string>
+ <string name="map_work" msgid="1360474076921878088">"직장 주소 보기"</string>
+ <string name="map_other" msgid="5560707927535653892">"기타 주소 보기"</string>
+ <string name="map_custom" msgid="6184363799976265281">"<xliff:g id="CUSTOM">%s</xliff:g> 주소 보기"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"AIM으로 채팅"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Windows Live로 채팅"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Yahoo로 채팅"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Skype로 채팅"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"QQ로 채팅"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Google 토크로 채팅"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"ICQ로 채팅"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Jabber로 채팅"</string>
+ <string name="chat" msgid="9025361898797412245">"채팅"</string>
+ <string name="postal_street" msgid="8133143961580058972">"번지"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"사서함"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"인근 지역"</string>
+ <string name="postal_city" msgid="6597491300084895548">"시/군/구"</string>
+ <string name="postal_region" msgid="6045263193478437672">"시/도"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"우편번호"</string>
+ <string name="postal_country" msgid="7638264508416368690">"국가"</string>
+ <string name="name_given" msgid="1687286314106019813">"이름"</string>
+ <string name="name_family" msgid="3416695586119999058">"성"</string>
+ <string name="name_prefix" msgid="59756378548779822">"이름 접두어"</string>
+ <string name="name_middle" msgid="8467433655992690326">"이름"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"이름 접미어"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"이름(소리나는 대로)"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"이름(소리나는 대로)"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"성(소리나는 대로)"</string>
+ <string name="split_label" msgid="8262112659919449087">"분할"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"데이터를 독립된 연락처로 만듭니다."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"<xliff:g id="SOURCE">%1$s</xliff:g> 계정: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> 연락처"</string>
+ <string name="from_account_format" msgid="687567483928582084">"출처: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"사진 사용"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> 연락처 정보는 이 기기에서 수정할 수 없습니다."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"연락처에 대한 추가 정보가 없습니다."</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 4d9cefb..2f14dd8 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Kontakter"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Telefon"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefon"</string>
<string name="shortcutContact" msgid="749243779392912958">"Kontakt"</string>
- <string name="shortcutDialContact" msgid="7165340343023469996">"Ring"</string>
- <string name="shortcutMessageContact" msgid="3025782962770298900">"Send melding"</string>
+ <string name="shortcutDialContact" msgid="746622101599186779">"Ring"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Send melding"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"Velg en kontaktsnarvei"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"Velg et nummer å ringe"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Velg et nummer å sende melding til"</string>
@@ -40,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Vis strekkode"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Rediger kontakt"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Slett kontakt"</string>
- <string name="menu_call" msgid="7359207953236681606">"Ring"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Send SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Ring kontakt"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Send SMS til kontakt"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Send e-post"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Se i kart"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Gjør til foretrukket nummer"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Bruk som standard e-post"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Del"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Del kontakt"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Kontakt delt"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Del opp kontakt"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Er du sikker på at du ønsker å dele opp denne kontakten i flere, en for hvert sett med kontaktinformasjon som den er satt sammen av?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Foren"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Vis kilder"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Skjul kilder"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Foren kontakt"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Slå sammen kontakter"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Velg kontakten du ønsker å slå sammen med <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Vis alle kontakter"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Forslag"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Alle kontakter"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Kontaktene er forent"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Alternativer"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Alternativer"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Slett"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Du kan ikke slette kontoer fra skrivebeskyttede kontoer, men du kan skjule dem i kontaktlistene."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Denne kontakten inneholder informasjon fra flere kontoer. Informasjon fra skrivebeskyttede kontoer vil bli skjult i kontaktlistene, ikke slettet."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Sletter du denne kontakten, vil du slette informasjon fra flere kontoer."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Denne kontakten vil bli slettet."</string>
<string name="menu_done" msgid="796017761764190697">"Lagre"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Tilbakestill"</string>
@@ -55,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonetisk"</string>
<string name="label_notes" msgid="8337354953278341042">"Notater"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Ringetone"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Grupper"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Rediger grupper"</string>
<string name="ghostData_name" msgid="6490954238641157585">"For- og etternavn"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Fonetisk navn"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Firma"</string>
@@ -64,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Telefonnummer"</string>
<string name="ghostData_email" msgid="6184537075551565919">"E-postadresse"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Postadresse"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Vis gruppe"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Kontakten finnes ikke."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Opprett ny kontakt"</string>
<string name="selectLabel" msgid="4255424123394910733">"Velg etikett"</string>
@@ -80,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Det er ingen bilder på telefonen."</string>
<string name="attachToContact" msgid="8820530304406066714">"Kontaktikon"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Egendefinert etikett"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Vis gruppe"</string>
- <string name="syncGroupPreference" msgid="9028361137161162861">"Rediger synkr. Grp."</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Vis grupper"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Vis grupper"</string>
+ <string name="syncGroupPreference" msgid="9028361137161162861">"Rediger synkr. grp."</string>
<string name="importFromSim" msgid="8383900146531125319">"Importer kontakter"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Send anrop direkte til telefonsvarer."</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Anrop blir sendt direkte til telefonsvarer."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Standardvalg"</string>
<string name="addPicture" msgid="1594679312161537678">"Legg til ikon"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Endre ikon"</string>
<string name="removePicture" msgid="3041230993155966350">"Fjern ikon"</string>
<string name="noContacts" msgid="8579310973261953559">"Ingen kontakter."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Fant ingen kontakter."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Ingen kontakter med telefonnummer."</string>
<string name="noFavorites" msgid="812766386743315815">"Ingen favoritter."</string>
<string name="select_group_title" msgid="7955698611959835612">"Grupper"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Gruppen «<xliff:g id="GROUPNAME">%s</xliff:g>» er tom."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Alle kontakter"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Kun kontakter med telefon"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Vis kun kontakter med telefonnummer"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Kontaktgrupper"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> kontakter"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> kontakter, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> med telefoner"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Synkroniser alle kontakter"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Mine kontakter"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Mine kontakter"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Kontakter med telefonnummer"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Stjernemerket i Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Lagrer kontakt…"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Lagrer viste grupper…"</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Kontakt opprettet."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Kontakt lagret."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Kunne ikke lagre kontaktendringene."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Ring nummer"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Telefonnummer"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Send SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Send SMS/MMS"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Send e-post"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"E-postadresser"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Send lynmelding"</string>
@@ -110,24 +150,42 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Se i kart"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Postadresser"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organisasjoner"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Grupper"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Annen informasjon"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Andre alternativer"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Mer"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Viser 1 kontakt med telefonnummer"</item>
+ <item quantity="other" msgid="6133262880804110289">"Viser <xliff:g id="COUNT">%d</xliff:g> kontakter med telefonnumre"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Ingen synlige kontakter med telefonnummer"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Viser 1 kontakt"</item>
+ <item quantity="other" msgid="2865867557378939630">"Viser <xliff:g id="COUNT">%d</xliff:g> kontakter"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Ingen synlige kontakter"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"Fant 1 kontakt"</item>
+ <item quantity="other" msgid="7752927996850263152">"Fant <xliff:g id="COUNT">%d</xliff:g> kontakter"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Fant ingen kontakter"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Sosial"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Alle"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Vanlige"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Telefon"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Logg"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Alle kontakter"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Kontakter med stjerne"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Kontakter med telefonnummer"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Send SMS-melding"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Send SMS-melding"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Ring <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Rediger nummer før anrop"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Legg til kontakter"</string>
<string name="recentCalls_removeFromRecentList" msgid="401662244636511330">"Fjern fra anropslogg"</string>
- <string name="recentCalls_deleteAll" msgid="6352364392762163704">"Nullstill anropslogg"</string>
+ <string name="recentCalls_deleteAll" msgid="6352364392762163704">"Tøm anropslogg"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Anropsloggen er tom."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Telefonsvarer"</string>
<string name="unknown" msgid="740067747858270469">"Ukjent"</string>
<string name="private_num" msgid="6374339738119166953">"Skjult nummer"</string>
@@ -137,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Henter fra SIM-kort…"</string>
<string name="simContacts_title" msgid="27341688347689769">"Kontakter på SIM-kort"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Synkroniser Google-kontaktene dine!"</font>" "\n"Etter å ha synkronisert telefonen vil kontaktene dine bli tilgjengelig overalt."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Du har ingen kontakter."\n\n"For å legge til kontakter, trykk "<font fgcolor="#ffffffff"><b>"menyknappen"</b></font>" og velg:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å lage en ny kontakt fra grunnen av"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer kontakter"</b></font>" for å legge til kontakter fra SIM-kortet"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Du har ingen kontakter."\n\n"For å legge til kontakter, trykk "<font fgcolor="#ffffffff"><b>"menyknappen"</b></font>" og velg:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Rediger synkroniserte grupper"</b></font>" for å legge til fra en ny eller eksisterende Google-konto"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å lage en ny kontakt fra grunnen av"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer kontakter"</b></font>" for å legge til kontakter fra SIM-kortet"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Du har ingen kontakter å vise. "\n\n"Slik legger du til en kontakt: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" og trykk deretter på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer"</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importér/eksportér"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Du har ingen kontakter å vise. (Hvis du nylig la til en konto, kan det ta noen minutter å synkronisere kontaktene.)"\n\n"Slik legger du til kontakter: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" og trykk deretter på: "\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer "</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativer"</b></font>" for å endre hvilke kontakter som vises"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importér/Eksportér"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Du har ingen kontakter å vise. "\n\n"Slik legger du til en kontakt: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" og trykk deretter på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer"</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importér/eksportér"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Du har ingen kontakter å vise. (Hvis du nylig la til en konto, kan det ta noen minutter å synkronisere kontaktene.)"\n\n"Slik legger du til kontakter: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" og trykk deretter på: "\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer "</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativer"</b></font>" for å endre hvilke kontakter som vises"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importér/Eksportér"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Du har ingen favoritter."\n\n"Slik legger du til en kontakt i favorittlisten:"\n\n" "<li>"Trykk på fanen "<b>"Kontakter"</b>" "\n</li>" "\n<li>"Trykk på kontakten du vil legge til i favoritter"\n</li>" "\n<li>"Trykk på stjernen ved siden av kontaktnavnet"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Velg grupper som skal synkroniseres"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Alle kontakter"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Alle kontakter"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Med stjerne"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Telefoner"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Bruk tonetastatur"</string>
@@ -171,8 +232,9 @@
<string name="returnCall" msgid="8171961914203617813">"Ring tilbake"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> min <xliff:g id="SECONDS">%s</xliff:g> sek"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Ofte ringt"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Legg til kontakt"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Legg til kontakt"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Legg til «<xliff:g id="EMAIL">%s</xliff:g>» som kontakt?"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Alle"</string>
<string name="description_image_button_one" msgid="1740638037139856139">"en"</string>
<string name="description_image_button_two" msgid="5882638439003731308">"to"</string>
<string name="description_image_button_three" msgid="8709731759376015180">"tre"</string>
@@ -185,43 +247,176 @@
<string name="description_image_button_star" msgid="3365919907520767866">"stjerne"</string>
<string name="description_image_button_zero" msgid="4133108949401820710">"null"</string>
<string name="description_image_button_pound" msgid="3039765597595889230">"firkant"</string>
- <string name="no_sdcard_title" msgid="6455416795090113715">"Mangler minnekort"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Fant ikke noe minnekort"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Leter etter VCard"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Mangler minnekort"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Fant ikke noe minnekort"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Leter etter VCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Hvor ønsker du å hente kontakter fra?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIM-kort"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"Minnekort"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importer alle VCard-filer"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Importer én VCard-filer"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Leter etter VCard-data på minnekort"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Kunne ikke scanne minnekort"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Kunne ikke scanne minnekort"</string>
- <string name="fail_reason_io_error" msgid="5922864781066136340">"Inn/ut-feil"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Klarte ikke å tolke VCard"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Fant ingen VCard-filer på minnekortet"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Fant ingen VCard-filer for valget ditt"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Velg VCard-fil"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Velg en VCard-fil som skal importeres"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Leser VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Leser VCard-fil(er)"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Importerer VCard-data"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Kunne ikke lese VCard-data"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"Kunne ikke lese VCard-data"\n"Feilårsak: «<xliff:g id="FAIL_REASON">%s</xliff:g>»"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importér fra SIM-kort"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importér fra minnekort"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Eksportér til minnekort"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importer én VCard-fil"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importer flere vCard-filer"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importer alle vCard-filer"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Leter etter VCard-data på minnekort"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Kunne ikke scanne minnekort"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Kunne ikke skanne minnekort (grunn: «<xliff:g id="FAIL_REASON">%s</xliff:g>»)"</string>
+ <string name="fail_reason_io_error" msgid="5922864781066136340">"Inn/ut-feil (årsak: «FAIL_REASON»)"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Kan ikke analysere VCard av uventet årsak"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Kan ikke analysere VCard selv om det ser ut til å være i riktig format, fordi den aktuelle implementeringen ikke støtter det."</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Fant ingen VCard-filer på minnekortet"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Fant ingen VCard-filer for valget ditt"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Importeringen av én eller flere filer mislyktes (%s)"</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Ukjent feil"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Velg VCard-fil"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Velg en VCard-fil som skal importeres"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Leser VCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Leser VCard-fil(er)"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Importerer VCard-data"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Kunne ikke lese VCard-data"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Kunne ikke lese VCard-data"\n"Feilårsak: «<xliff:g id="FAIL_REASON">%s</xliff:g>»"</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> av <xliff:g id="TOTAL_NUMBER">%s</xliff:g> kontakter"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> av <xliff:g id="TOTAL_NUMBER">%s</xliff:g> filer"</string>
+ <string name="export_all_contacts" msgid="2873892623335194071">"Alle kontakter"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Lokalt lagrede kontakter"</string>
<string name="export_contact_list" msgid="3165097742175874384">"Eksporter kontakter"</string>
- <string name="confirm_export_title" msgid="1693047909433122854">"Eksportbekreftelse"</string>
- <string name="confirm_export_message" msgid="63482084706768079">"Ønsker du å eksportere kontaktlisten din til «<xliff:g id="VCARD_FILENAME">%s</xliff:g>»?"</string>
- <string name="exporting_contact_failed_title" msgid="1455264422455075858">"Kunne ikke eksportere kontaktlisten"</string>
- <string name="exporting_contact_failed_message" msgid="1426451081541603512">"Kunne ikke eksportere kontaktlisten"\n"Feilårsak: «<xliff:g id="FAIL_REASON">%s</xliff:g>»"</string>
- <string name="fail_reason_too_many_vcard" msgid="5416992255233341607">"For mange VCard-datafiler på minnekortet"</string>
- <string name="fail_reason_too_long_filename" msgid="7105223965196949065">"Filnavnet ble for langt («<xliff:g id="FILENAME">%s</xliff:g>»)"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Eksportbekreftelse"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Vil du eksportere kontaktlisten din til «<xliff:g id="VCARD_FILENAME">%s</xliff:g>»?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Kunne ikke eksportere kontaktlisten"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Eksport av kontaktdata mislyktes"\n"Årsak til feil: «<xliff:g id="FAIL_REASON">%s</xliff:g>»"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Det finnes ingen eksporterbar kontakt."</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"For mange VCard-datafiler på minnekortet"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"For langt filnavn kreves («<xliff:g id="FILENAME">%s</xliff:g>»)"</string>
<string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Kan ikke åpne eller opprette målkatalogen «<xliff:g id="DIR_NAME">%s</xliff:g>»"</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"Eksporterer kontaktdata"</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"Eksporterer kontaktdata til «<xliff:g id="FILE_NAME">%s</xliff:g>»"</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Kunne ikke starte eksporteringen: «<xliff:g id="EXACT_REASON">%s</xliff:g>»"</string>
- <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"En feil oppsto under eksportering: «<xliff:g id="EXACT_REASON">%s</xliff:g>»"</string>
- <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Klarte ikke å åpne «<xliff:g id="FILE_NAME">%s</xliff:g>»: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Det oppstod feil ved eksport: «<xliff:g id="EXACT_REASON">%s</xliff:g>»"</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Klarte ikke å hente databaseinformasjon"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Det finnes ingen eksporterbar kontakt."</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"Objektet for vCard-redigering er ikke riktig initialisert"</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Kunne ikke åpne «<xliff:g id="FILE_NAME">%s</xliff:g>»: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> av <xliff:g id="TOTAL_NUMBER">%s</xliff:g> kontakter"</string>
<string name="search_settings_description" msgid="2675223022992445813">"Navn på kontakter"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Legg til pause på 2 sek."</string>
+ <string name="add_wait" msgid="3360818652790319634">"Legg til Vent"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Ring"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Ring med"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Send SMS med"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Husk dette valget"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Ingen programmer som kan utføre denne handlingen ble funnet"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Husk dette valget"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Ukjent"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Kontoer"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Import/eksport"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importér/eksportér kontakter"</string>
+ <string name="menu_share" msgid="943789700636542260">"Del"</string>
+ <string name="share_via" msgid="563121028023030093">"Del kontakt via"</string>
+ <string name="share_error" msgid="4374508848981697170">"Kan ikke dele kontakten."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Navn"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Kallenavn"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisering"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Nettsted"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Aktivitet"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"H"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"J"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"A"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Kontakten er skrivebeskyttet"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Andre detaljer"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Hovednavn"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Opprett kontakt under konto"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Fjern synkronisert gruppe"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Legg til synkronisert gruppe"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Flere grupper…"</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"(Ugrupperte kontakter)"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Alle kontakter"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Hvis «<xliff:g id="GROUP">%s</xliff:g>» fjernes·fra synkroniseringen, vil også alle ugrupperte kontakter fjernes fra synkroniseringen."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Kun telefon (usynkronisert)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Visningsnavn"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Ring <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Ring (privat)"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Ring mobil"</string>
+ <string name="call_work" msgid="5328785911463744028">"Ring (arbeid)"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Anrop faks (arbeid)"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Anrop faks (privat)"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Ring personsøker"</string>
+ <string name="call_other" msgid="5605584621798108205">"Ring annet"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Ring tilbakering"</string>
+ <string name="call_car" msgid="3280537320306436445">"Ring (bil)"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Ring firma (sentralbord)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Ring ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Ring hovednummer"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Ring annen faks"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Ring (radio)"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Ring teleks"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Ring teksttelefon"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Ring arbeidsmobil"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Ring arbeidspersonsøker"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Ring <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Ring MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Send SMS (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Send SMS (privat)"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Send SMS (mobil)"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Send SMS (arbeid)"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Send SMS til faks (arbeid)"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Send SMS til faks (privat)"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Send SMS (personsøker)"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Send SMS (annet)"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Send SMS til tilbakeringer"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Send SMS (bil)"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Send SMS til firma (sentralbord)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Send SMS til ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Send SMS til hovednummer"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Send SMS til annen faks"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Send SMS (radio)"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Send SMS til teleks"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Send SMS til teksttelefon"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Send SMS til arbeidsmobil"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Send SMS til arbeidspersonsøker"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Send SMS til <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Send MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"Send e-post (privat)"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Skriv e-post (mobil)"</string>
+ <string name="email_work" msgid="2807430017302722689">"Send e-post (arbeid)"</string>
+ <string name="email_other" msgid="8093933498541795832">"Send e-post (annet)"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Send e-post (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="email" msgid="5668400997660065897">"E-post"</string>
+ <string name="map_home" msgid="1243547733423343982">"Vis privat adresse"</string>
+ <string name="map_work" msgid="1360474076921878088">"Vis jobbadresse"</string>
+ <string name="map_other" msgid="5560707927535653892">"Vis andre adresser"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Vis <xliff:g id="CUSTOM">%s</xliff:g> adresse"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Nettprat med AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Nettprat med Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Nettprat med Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Nettprat med Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Nettprat med QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Nettprat med Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Nettprat med ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Nettprat med Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Nettprat"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Gate"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Postboks"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Nabolag"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Poststed"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Poststed"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postnummer"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Land"</string>
+ <string name="name_given" msgid="1687286314106019813">"Fornavn"</string>
+ <string name="name_family" msgid="3416695586119999058">"Etternavn"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Første del av navn"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Mellomnavn"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Navnesuffiks"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Fonetisk fornavn"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetisk mellomnavn"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Fonetisk etternavn"</string>
+ <string name="split_label" msgid="8262112659919449087">"Del opp"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Gjør disse dataene om til en egen kontakt."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Fra <xliff:g id="SOURCE">%1$s</xliff:g>-konto: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g>-kontakt"</string>
+ <string name="from_account_format" msgid="687567483928582084">"fra <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Bruk dette bildet"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g>-kontaktinformasjon kan ikke redigeres på denne enheten."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Ingen utfyllende informasjon for denne kontakten"</string>
</resources>
diff --git a/res/values-nl/config.xml b/res/values-nl/config.xml
deleted file mode 100644
index 07b3c7e..0000000
--- a/res/values-nl/config.xml
+++ /dev/null
@@ -1,28 +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">
- <!-- no translation found for config_export_vcard_type (9145748078116159716) -->
- <skip />
- <string name="config_export_dir" msgid="222182743639478636">"/sdcard"</string>
- <!-- no translation found for config_export_file_prefix (3022868431158658122) -->
- <skip />
- <!-- no translation found for config_export_file_suffix (16505844221142195) -->
- <skip />
- <string name="config_export_file_extension" msgid="1758878818611339161">"vcf"</string>
- <!-- no translation found for config_export_extensions_to_consider (5095044502091950623) -->
- <skip />
-</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 08c2f86..f538705 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Contacten"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Telefoon"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefoon"</string>
<string name="shortcutContact" msgid="749243779392912958">"Contacten"</string>
- <string name="shortcutDialContact" msgid="7165340343023469996">"Direct bellen"</string>
- <string name="shortcutMessageContact" msgid="3025782962770298900">"Direct bericht"</string>
+ <string name="shortcutDialContact" msgid="746622101599186779">"Direct bellen"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Direct bericht"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"Kies een contactsnelkoppeling"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"Kies een nummer om te bellen"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Kies een nummer voor bericht"</string>
@@ -40,12 +40,37 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Barcode weergeven"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Contact bewerken"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Contact verwijderen"</string>
- <string name="menu_call" msgid="7359207953236681606">"Bellen"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"SMS/MMS verzenden"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Contact bellen"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Sms\'en naar contact"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"E-mail verzenden"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Adres op kaart weergeven"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Als standaardnummer instellen"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Instellen als standaard e-mailadres"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Scheiden"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Contact splitsen"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Contacten gescheiden"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Contacten scheiden"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Weet u zeker dat u dit enkele contact wilt scheiden in meerdere contacten: één contact voor elke verzameling contactgegevens die aan het contact is gekoppeld?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Samenvoegen"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Bronnen weergeven"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Bronnen verbergen"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Contact samenvoegen"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Contacten samenvoegen"</string>
+ <!-- no translation found for blurbJoinContactDataWith (995870557595050304) -->
+ <skip />
+ <!-- no translation found for showAllContactsJoinItem (2189695051430392383) -->
+ <skip />
+ <!-- no translation found for separatorJoinAggregateSuggestions (2831414448851313345) -->
+ <skip />
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Alle contacten"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Contacten zijn samengevoegd"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Opties"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Opties"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Verwijderen"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"U kunt contacten niet verwijderen uit alleen-lezen accounts, maar u kunt ze verbergen in uw contactenlijst."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Dit contact bevat gegevens uit meerdere accounts. Gegevens uit alleen-lezen accounts worden verborgen in uw contactenlijst, maar niet verwijderd."</string>
+ <!-- no translation found for multipleContactDeleteConfirmation (938900978442960800) -->
+ <skip />
<string name="deleteConfirmation" msgid="811706994761610640">"Dit contact wordt verwijderd."</string>
<string name="menu_done" msgid="796017761764190697">"Gereed"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Terugkeren"</string>
@@ -55,6 +80,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonetisch"</string>
<string name="label_notes" msgid="8337354953278341042">"Opmerkingen"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Beltoon"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Groepen"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Groepen bewerken"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Voor- en achternaam"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Fonetisch gespelde naam"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Bedrijf"</string>
@@ -64,6 +92,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Telefoonnummer"</string>
<string name="ghostData_email" msgid="6184537075551565919">"E-mailadres"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Postadres"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Groep weergeven"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Het contact bestaat niet."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Nieuw contact maken"</string>
<string name="selectLabel" msgid="4255424123394910733">"Label selecteren"</string>
@@ -80,29 +109,45 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Er zijn geen foto\'s beschikbaar op de telefoon."</string>
<string name="attachToContact" msgid="8820530304406066714">"Pictogram voor contact"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Aangepaste labelnaam"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Groep weergeven"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Weergaveopties"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Weergaveopties"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Sync.groepen bewerken"</string>
<string name="importFromSim" msgid="8383900146531125319">"Contacten importeren"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Oproepen rechtstreeks naar voicemail verzenden"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Oproepen worden rechtstreeks naar voicemail verzonden."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Standaard"</string>
<string name="addPicture" msgid="1594679312161537678">"Pictogram toevoegen"</string>
+ <!-- no translation found for changePicture (2943329047610967714) -->
+ <skip />
<string name="removePicture" msgid="3041230993155966350">"Pictogram verwijderen"</string>
<string name="noContacts" msgid="8579310973261953559">"Geen contacten."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Kan geen overeenkomende contacten vinden."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Geen contacten met telefoonnummers."</string>
<string name="noFavorites" msgid="812766386743315815">"Geen favorieten."</string>
<string name="select_group_title" msgid="7955698611959835612">"Groepen"</string>
<string name="groupEmpty" msgid="6661950109828194595">"De groep \'<xliff:g id="GROUPNAME">%s</xliff:g>\' is leeg."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Alle contacten"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Alleen contacten met telefoonnummers"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Alleen contacten weergeven met telefoonnummers"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Contacten voor weergave kiezen"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> contacten"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> contacten, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> met telefoonnummers"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Alle contacten synchroniseren"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Mijn contacten"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Mijn contacten"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Contacten met telefoonnummers"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Met ster in Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Contact opslaan..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Weergaveopties opslaan..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Contact is gemaakt."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Contact opgeslagen."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Fout. Kan wijzigingen in contact niet opslaan."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Nummer bellen"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Telefoonnummers"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"SMS/MMS verzenden"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Sms verzenden"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"E-mail verzenden"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"E-mailadressen"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Chatbericht verzenden"</string>
@@ -110,17 +155,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Adres op kaart weergeven"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Postadressen"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organisaties"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Groepen"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Overige informatie"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Andere opties"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Meer"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"1 contact met telefoonnummer"</item>
+ <item quantity="other" msgid="6133262880804110289">"<xliff:g id="COUNT">%d</xliff:g> contacten met telefoonnummers"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Geen zichtbare contacten met telefoonnummers"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"1 contact"</item>
+ <item quantity="other" msgid="2865867557378939630">"<xliff:g id="COUNT">%d</xliff:g> contacten"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Geen zichtbare contacten"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"1 contact gevonden"</item>
+ <item quantity="other" msgid="7752927996850263152">"<xliff:g id="COUNT">%d</xliff:g> contacten gevonden"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Contact niet gevonden"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Sociaal"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contact"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriet"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Telefoon"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefoon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Gesprek"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Alle contacten"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Contacten met ster"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Contacten met telefoonnummers"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"SMS-bericht verzenden"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Sms verzenden"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"<xliff:g id="NAME">%s</xliff:g> bellen"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Nummer bewerken voor bellen"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Toevoegen aan contacten"</string>
@@ -128,6 +190,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Gesprekken wissen"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Gesprekken is leeg"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Voicemail"</string>
<string name="unknown" msgid="740067747858270469">"Onbekend"</string>
<string name="private_num" msgid="6374339738119166953">"Privénummer"</string>
@@ -137,10 +200,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Laden vanaf SIM-kaart..."</string>
<string name="simContacts_title" msgid="27341688347689769">"Contacten op SIM-kaart"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Synchroniseer uw Google-contacten!"</font>" "\n"Zodra uw telefoon is gesynchroniseerd, heeft u uw contacten altijd ter beschikking."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"U heeft geen contacten."\n\n"Als u contacten wilt toevoegen, drukt u op "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" en selecteert u:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Nieuw contact"</b></font>" om een nieuw contact te maken"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Contacten importeren"</b></font>" om contacten vanaf uw SIM-kaart toe te voegen"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"U heeft geen contacten."\n\n"Als u contacten wilt toevoegen, klikt u op "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" en selecteert u:"\n\n<li><font fgcolor="#ffffffff"><b>"\'Synchronisatiegroepen bewerken\'"</b></font>" om contacten toe te voegen uit een nieuw of bestaand Google-account"\n</li>\n" "<li><font fgcolor="#ffffffff"><b>"\'Nieuw contact\'"</b></font>" om een geheel nieuw contact te maken"\n</li>\n" "<li><font fgcolor="#ffffffff"><b>"\'Contacten importeren\'"</b></font>" om contacten te importeren vanaf uw SIM-kaart"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"U heeft geen contacten om weer te geven."\n\n"Als u contacten wilt toevoegen, drukt u op "<font fgcolor="#ffffffff"><b>"\'Menu\'"</b></font>" en raakt u de volgende opties aan:"\n" "\n<li><font fgcolor="#ffffffff"><b>"\'Accounts\'"</b></font>" om een account toe te voegen of een account te configureren met contacten die u kunt synchroniseren met de telefoon"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"\'Nieuw contact\'"</b></font>" om een geheel nieuw contact te maken"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"\'Importeren/exporteren\'"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"U heeft geen contacten om weer te geven. (Als u net een account heeft toegevoegd, kan het enkele minuten duren voordat de contacten zijn gesynchroniseerd.)"\n\n"Als u contacten wilt toevoegen, drukt u op "<font fgcolor="#ffffffff"><b>"\'Menu\'"</b></font>" en raakt u de volgende opties aan:"\n" "\n<li><font fgcolor="#ffffffff"><b>"\'Accounts\'"</b></font>" om een account toe te voegen of een account te configureren met contacten die u kunt synchroniseren met de telefoon"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"\'Weergaveopties\'"</b></font>" om de zichtbaarheid van contacten te wijzigen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"\'Nieuw contact\'"</b></font>" om een geheel nieuw contact te maken"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"\'Importeren/exporteren\'"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"U heeft geen contacten om weer te geven."\n\n"Als u contacten wilt toevoegen, drukt u op "<font fgcolor="#ffffffff"><b>"\'Menu\'"</b></font>" en raakt u de volgende opties aan:"\n" "\n<li><font fgcolor="#ffffffff"><b>"\'Account "</b></font>" om een account toe te voegen of een account te configureren met contacten die u kunt synchroniseren met de telefoon"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"\'Nieuw contact\'"</b></font>" om een geheel nieuw contact te maken"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"\'Importeren/exporteren\'"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"U heeft geen contacten om weer te geven. (Als u net een account heeft toegevoegd, kan het enkele minuten duren voordat de contacten zijn gesynchroniseerd.)"\n\n"Als u contacten wilt toevoegen, drukt u op "<font fgcolor="#ffffffff"><b>"\'Menu\'"</b></font>" en raakt u de volgende opties aan:"\n" "\n<li><font fgcolor="#ffffffff"><b>"\'Accounts\'"</b></font>" om een account toe te voegen of een account te configureren met contacten die u kunt synchroniseren met de telefoon"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"\'Weergaveopties\'"</b></font>" om de zichtbaarheid van contacten te wijzigen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"\'Nieuw contact\'"</b></font>" om een geheel nieuw contact te maken"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"\'Importeren/exporteren\'"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"U heeft geen favorieten."\n\n"U kunt als volgt een contact toevoegen aan uw lijst met favorieten:"\n\n" "<li>"Raak het tabblad \'"<b>"Contacten"</b>"\' aan."\n</li>" "\n<li>"Raak het contact aan dat u wilt toevoegen aan uw favorieten."\n</li>" "\n<li>"Raak de ster aan die wordt weergegeven naast de naam van het contact."\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Groepen selecteren om te synchroniseren"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Alle contacten"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Alle contacten"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Met ster"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Telefoons"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Toetsen voor toonkiezen gebruiken"</string>
@@ -171,8 +237,9 @@
<string name="returnCall" msgid="8171961914203617813">"Terugbellen"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> min. <xliff:g id="SECONDS">%s</xliff:g> sec."</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Vaak gebeld"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Contact toevoegen"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Contact toevoegen"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"\"<xliff:g id="EMAIL">%s</xliff:g>\" toevoegen aan contacten?"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Alles"</string>
<string name="description_image_button_one" msgid="1740638037139856139">"één"</string>
<string name="description_image_button_two" msgid="5882638439003731308">"twee"</string>
<string name="description_image_button_three" msgid="8709731759376015180">"drie"</string>
@@ -185,43 +252,186 @@
<string name="description_image_button_star" msgid="3365919907520767866">"ster"</string>
<string name="description_image_button_zero" msgid="4133108949401820710">"nul"</string>
<string name="description_image_button_pound" msgid="3039765597595889230">"hekje"</string>
- <string name="no_sdcard_title" msgid="6455416795090113715">"Geen SD-kaart"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Geen SD-kaart gedetecteerd"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Zoeken naar VCard"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Geen SD-kaart"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Geen SD-kaart gedetecteerd"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Zoeken naar vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Waarvandaan wilt u contacten importeren?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIM-kaart"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"SD-kaart"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Alle VCard-bestanden importeren"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Eén VCard-bestand importeren"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Zoeken naar VCard-gegevens op VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Scannen van SD-kaart is mislukt"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Scannen van SD-kaart is mislukt"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importeren van SIM-kaart"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importeren van SD-kaart"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Exporteren naar SD-kaart"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Eén vCard-bestand importeren"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Meerdere vCard-bestanden importeren"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Alle vCard-bestanden importeren"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Zoeken naar vCard-gegevens op SD-kaart"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Scannen van SD-kaart is mislukt"</string>
+ <!-- no translation found for scanning_sdcard_failed_message (3761992500690182922) -->
+ <skip />
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O-fout"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Parseren van VCard is mislukt"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Geen VCard-bestand gevonden op SD-kaart"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Geen geldig VCard-item gevonden voor uw selectie"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"VCard-bestand selecteren"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Selecteer een VCard-bestand om te importeren"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"VCard lezen"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"VCard-bestand(en) lezen"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"VCard-gegevens importeren"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Lezen van VCard-gegevens is mislukt"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"VCard-gegevens kunnen niet worden gelezen"\n"Reden voor fout: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\'"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Parseren van vCard is mislukt om onbekende reden"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Kan vCard niet parseren, ook al lijkt de indeling geldig. vCard wordt niet ondersteund door de huidige implementatie"</string>
+ <!-- no translation found for fail_reason_no_vcard_file (6376516175882881595) -->
+ <skip />
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Geen geldig vCard-item gevonden voor uw selectie"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Een of meer bestanden kunnen niet worden geïmporteerd (%s)"</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Onbekende fout"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"vCard-bestand selecteren"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Selecteer een vCard-bestand om te importeren"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"vCard lezen"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"vCard-bestand(en) lezen"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"vCard-gegevens importeren"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Lezen van vCard-gegevens is mislukt"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Kan vCard niet lezen."\n"Reden voor de fout: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\'"</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> van <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contacten"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> van <xliff:g id="TOTAL_NUMBER">%s</xliff:g> bestanden"</string>
+ <string name="export_all_contacts" msgid="2873892623335194071">"Alle contacten"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Lokaal opgeslagen contacten"</string>
<string name="export_contact_list" msgid="3165097742175874384">"Contacten exporteren"</string>
- <string name="confirm_export_title" msgid="1693047909433122854">"Bevestiging voor export"</string>
- <string name="confirm_export_message" msgid="63482084706768079">"Mag uw contactenlijst worden geëxporteerd naar \'<xliff:g id="VCARD_FILENAME">%s</xliff:g>\'?"</string>
- <string name="exporting_contact_failed_title" msgid="1455264422455075858">"Exporteren van contactgegevens is mislukt"</string>
- <string name="exporting_contact_failed_message" msgid="1426451081541603512">"Exporteren van contactgegevens is mislukt"\n"Reden voor fout: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\'"</string>
- <string name="fail_reason_too_many_vcard" msgid="5416992255233341607">"Te veel VCard-gegevens op de SD-kaart"</string>
- <string name="fail_reason_too_long_filename" msgid="7105223965196949065">"Te lange bestandsnaam vereist (\'<xliff:g id="FILENAME">%s</xliff:g>\')"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Exporteren bevestigen"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Weet u zeker dat u uw lijst met contacten wilt exporteren naar \'<xliff:g id="VCARD_FILENAME">%s</xliff:g>\'?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Exporteren van contactgegevens mislukt"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Exporteren van contactgegevens mislukt."\n"Reden voor de fout: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\'"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Er is geen contact dat geëxporteerd kan worden"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Te veel vCard-gegevens op de SD-kaart"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Vereiste bestandsnaam is te lang (\'<xliff:g id="FILENAME">%s</xliff:g>\')"</string>
<string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Kan de doeldirectory \'<xliff:g id="DIR_NAME">%s</xliff:g>\' niet openen of maken"</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"Contactgegevens exporteren"</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"Contactgegevens exporteren naar \'<xliff:g id="FILE_NAME">%s</xliff:g>\'"</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Kan het exportprogramma niet initialiseren: \'<xliff:g id="EXACT_REASON">%s</xliff:g>\'"</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Fout opgetreden tijdens export: \'<xliff:g id="EXACT_REASON">%s</xliff:g>\'"</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Databasegegevens ophalen mislukt"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Er is geen contact dat geëxporteerd kan worden. Mogelijk heeft u niet-exporteerbare gegevens gekozen."</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"De vCard-editor is niet juist geïnitialiseerd"</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Kan \'<xliff:g id="FILE_NAME">%s</xliff:g>\' niet openen: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> van <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contacten"</string>
<string name="search_settings_description" msgid="2675223022992445813">"Namen van uw contacten"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Pauze van 2 seconden toevoegen"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Wachten toevoegen"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Bellen"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Bellen met"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Sms\'en met"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Deze keuze onthouden"</string>
+ <!-- no translation found for quickcontact_missing_app (4600366393134289038) -->
+ <skip />
+ <!-- no translation found for quickcontact_remember_choice (5964536411579749424) -->
+ <skip />
+ <!-- no translation found for quickcontact_missing_name (5590266114306996632) -->
+ <skip />
+ <string name="menu_accounts" msgid="8499114602017077970">"Accounts"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importeren/exporteren"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Contacten importeren/exporteren"</string>
+ <string name="menu_share" msgid="943789700636542260">"Delen"</string>
+ <string name="share_via" msgid="563121028023030093">"Contact delen via"</string>
+ <string name="share_error" msgid="4374508848981697170">"Dit contact kan niet worden gedeeld."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Naam"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Bijnaam"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisatie"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
+ <!-- no translation found for eventLabelsGroup (8069912895912714412) -->
+ <skip />
+ <string name="type_short_home" msgid="7770424864090605384">"H"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"W"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"O"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Dit contact is alleen-lezen"</string>
+ <!-- no translation found for edit_secondary_collapse (5371618426594477103) -->
+ <skip />
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Primaire naam"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Contact in account maken"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Synchronisatiegroep verwijderen"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Synchronisatiegroep toevoegen"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Meer groepen…"</string>
+ <!-- no translation found for display_ungrouped (4602580795576261158) -->
+ <skip />
+ <!-- no translation found for display_all_contacts (6846131371214707956) -->
+ <skip />
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Als u \'<xliff:g id="GROUP">%s</xliff:g>\' verwijdert uit de synchronisatie, worden ook contacten die niet bij een groep horen uit de synchronisatie verwijderd."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Alleen voor telefoon (niet gesynchroniseerd)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Weergavenaam"</string>
+ <string name="call_custom" msgid="7756571794763171802">"<xliff:g id="CUSTOM">%s</xliff:g> bellen"</string>
+ <string name="call_home" msgid="1990519474420545392">"Bellen naar huis"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Bellen naar mobiel"</string>
+ <string name="call_work" msgid="5328785911463744028">"Bellen naar werk"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Bellen naar fax werk"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Bellen naar huisfax"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Bellen naar pager"</string>
+ <string name="call_other" msgid="5605584621798108205">"Bellen naar overig"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Bellen naar terugbelnummer"</string>
+ <string name="call_car" msgid="3280537320306436445">"Bellen naar autotelefoon"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Bellen naar hoofdkantoor"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Bellen naar ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Bellen naar algemeen nummer"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Bellen naar andere fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Bellen naar radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Telex bellen"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Tekststelefoon bellen"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Bellen naar mobiel werk"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Bellen naar pager werk"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"<xliff:g id="ASSISTANT">%s</xliff:g> bellen"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Bellen via MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Sms\'en naar <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Sms\'en naar huis"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Sms\'en naar mobiel"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Sms\'en naar werk"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Sms\'en naar fax werk"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Sms\'en naar huisfax"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Sms\'en naar pager"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Sms\'en naar overig"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Sms\'en naar terugbelnummer"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Sms\'en naar autotelefoon"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Sms\'en naar hoofdkantoor"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Sms\'en naar ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Sms\'en naar algemeen nummer"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Sms\'en naar andere fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Sms\'en naar radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Sms\'en naar telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Sms\'en naar teksttelefoon"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Sms\'en naar mobiel werk"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Sms\'en naar werkpager"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Sms\'en naar <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Sms\'en via MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"E-mailen naar huis"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-mailen naar mobiel"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-mailen naar werk"</string>
+ <string name="email_other" msgid="8093933498541795832">"E-mailen naar overig"</string>
+ <string name="email_custom" msgid="7548003991586214105">"E-mailadres <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-mail"</string>
+ <string name="map_home" msgid="1243547733423343982">"Thuisadres weergeven"</string>
+ <string name="map_work" msgid="1360474076921878088">"Werkadres weergeven"</string>
+ <string name="map_other" msgid="5560707927535653892">"Andere adressen weergeven"</string>
+ <string name="map_custom" msgid="6184363799976265281">"<xliff:g id="CUSTOM">%s</xliff:g> adres weergeven"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chatten via AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chatten via Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chatten via Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chatten via Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chatten via QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chatten via Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chatten via ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chatten via Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Straat"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Postbus"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Wijk"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Plaats"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Staat"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postcode"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Land"</string>
+ <string name="name_given" msgid="1687286314106019813">"Roepnaam"</string>
+ <string name="name_family" msgid="3416695586119999058">"Achternaam"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Voorvoegsel"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Tweede voornaam"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Achtervoegsel van naam"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Fonetische roepnaam"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetische tweede voornaam"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Fonetische achternaam"</string>
+ <string name="split_label" msgid="8262112659919449087">"Splitsen"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Maak van deze gegevens een nieuw contact."</string>
+ <!-- no translation found for account_name_format (4421123930035299208) -->
+ <skip />
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> contact"</string>
+ <string name="from_account_format" msgid="687567483928582084">"van <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Deze foto gebruiken"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"Contactgegevens van <xliff:g id="SOURCE">%1$s</xliff:g> kunnen niet worden bewerkt op dit apparaat."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Geen extra gegevens voor dit contact"</string>
</resources>
diff --git a/res/values-pl/config.xml b/res/values-pl/config.xml
deleted file mode 100644
index 07b3c7e..0000000
--- a/res/values-pl/config.xml
+++ /dev/null
@@ -1,28 +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">
- <!-- no translation found for config_export_vcard_type (9145748078116159716) -->
- <skip />
- <string name="config_export_dir" msgid="222182743639478636">"/sdcard"</string>
- <!-- no translation found for config_export_file_prefix (3022868431158658122) -->
- <skip />
- <!-- no translation found for config_export_file_suffix (16505844221142195) -->
- <skip />
- <string name="config_export_file_extension" msgid="1758878818611339161">"vcf"</string>
- <!-- no translation found for config_export_extensions_to_consider (5095044502091950623) -->
- <skip />
-</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 8719d15..0592b5d 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Kontakty"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Telefon"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefon"</string>
<string name="shortcutContact" msgid="749243779392912958">"Kontakt"</string>
- <string name="shortcutDialContact" msgid="7165340343023469996">"Telefonowanie bezpośrednie"</string>
- <string name="shortcutMessageContact" msgid="3025782962770298900">"Wiadomość bezpośrednia"</string>
+ <string name="shortcutDialContact" msgid="746622101599186779">"Telefonowanie bezpośrednie"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Wiadomość bezpośrednia"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"Wybierz skrót kontaktu"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"Wybierz numer, aby nawiązać połączenie"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Wybierz numer, aby wysłać wiadomość"</string>
@@ -40,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Pokaż kod kreskowy"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Edytuj kontakt"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Usuń kontakt"</string>
- <string name="menu_call" msgid="7359207953236681606">"Zadzwoń"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Wyślij SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Zadzwoń do kontaktu"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Wyślij tekst do kontaktu"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Wyślij e-mail"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Pokaż adres na mapie"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Ustaw ten numer jako domyślny"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Ustaw jako domyślny adres e-mail"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Podziel"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Podziel kontakt"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Kontakty zostały podzielone"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Podziel kontakt"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Czy na pewno chcesz podzielić ten pojedynczy kontakt na kilka kontaktów: po jednym dla każdego zawartego w nim zestawu informacji kontaktowych?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Połącz"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Pokaż źródła"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Ukryj źródła"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Połącz kontakt"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Połącz kontakty"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Wybierz kontakt, który chcesz połączyć z <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Pokaż wszystkie kontakty"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Sugerowane kontakty"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Wszystkie kontakty"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Kontakty zostały połączone"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Opcje"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Opcje"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Usuń"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Nie możesz usunąć kontaktów z kont tylko do odczytu, ale możesz ukryć je na swoich listach kontaktów."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Ten kontakt zawiera informacje pochodzące z wielu kont. Informacje z kont przeznaczonych tylko do odczytu zostaną na listach kontaktów ukryte, a nie usunięte."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Usunięcie tego kontaktu spowoduje usunięcie informacji z wielu kont."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Ten kontakt zostanie usunięty."</string>
<string name="menu_done" msgid="796017761764190697">"Gotowe"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Przywróć"</string>
@@ -55,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonetycznie"</string>
<string name="label_notes" msgid="8337354953278341042">"Notatki"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Dzwonek"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Grupy"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Edytuj grupy"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Imię i nazwisko"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Nazwisko (fonetycznie)"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Firma"</string>
@@ -64,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Numer telefonu"</string>
<string name="ghostData_email" msgid="6184537075551565919">"Adres e-mail"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Adres pocztowy"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Wyświetl grupę"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Kontakt nie istnieje."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Utwórz nowy kontakt"</string>
<string name="selectLabel" msgid="4255424123394910733">"Wybierz etykietę"</string>
@@ -80,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"W telefonie brak dostępnych zdjęć."</string>
<string name="attachToContact" msgid="8820530304406066714">"Ikona kontaktu"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Nazwa etykiety niestandardowej"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Wyświetl grupę"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Opcje wyświetlania"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Opcje wyświetlania"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Synchronizacja grup"</string>
<string name="importFromSim" msgid="8383900146531125319">"Importuj kontakty"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Przekieruj połączenia bezpośrednio na pocztę głosową"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Połączenia są przekazywane bezpośrednio do poczty głosowej."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Domyślny"</string>
<string name="addPicture" msgid="1594679312161537678">"Dodaj ikonę"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Zmień ikonę"</string>
<string name="removePicture" msgid="3041230993155966350">"Usuń ikonę"</string>
<string name="noContacts" msgid="8579310973261953559">"Brak kontaktów"</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Nie znaleziono pasujących kontaktów."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Brak kontaktów z numerami telefonów"</string>
<string name="noFavorites" msgid="812766386743315815">"Brak ulubionych"</string>
<string name="select_group_title" msgid="7955698611959835612">"Grupy"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Grupa „<xliff:g id="GROUPNAME">%s</xliff:g>” jest pusta."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Wszystkie kontakty"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Tylko kontakty z numerami telefonów"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Wyświetlaj tylko kontakty zawierające numery telefonów"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Wybierz kontakty do wyświetlenia"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"Liczba kontaktów: <xliff:g id="COUNT">%0$d</xliff:g>"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"Liczba kontaktów: <xliff:g id="COUNT_0">%1$d</xliff:g>, liczba kontaktów z numerami telefonów: <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g>"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Synchronizuj wszystkie kontakty"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Moje kontakty"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Moje kontakty"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Kontakty z numerami telefonu"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Z gwiazdką w systemie Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Trwa zapisywanie kontaktu..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Trwa zapisywanie opcji wyświetlania..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Utworzono kontakt."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Kontakt został zapisany."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Błąd. Nie można zapisać zmian wprowadzonych w kontakcie."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Wybierz numer"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Numery telefonów"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Wyślij SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Wyślij tekst"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Wyślij e-mail"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"Adresy e-mail"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Wyślij wiadomość czatu"</string>
@@ -110,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Pokaż adres na mapie"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Adresy pocztowe"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organizacje"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Grupy"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Inne informacje"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Inne opcje"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Więcej"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Wyświetlanie 1 kontaktu z numerem telefonu"</item>
+ <item quantity="other" msgid="6133262880804110289">"Wyświetlanych kontaktów z numerami telefonów: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Brak widocznych kontaktów z numerami telefonów"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Wyświetlanie 1 kontaktu"</item>
+ <item quantity="other" msgid="2865867557378939630">"Wyświetlanych kontaktów: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Brak widocznych kontaktów"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"Znaleziono 1 kontakt"</item>
+ <item quantity="other" msgid="7752927996850263152">"Znalezionych kontaktów: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Nie znaleziono kontaktu"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Społeczeństwo"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakty"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Ulubione"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Telefon"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Rejestr"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Wszystkie kontakty"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Kontakty z gwiazdką"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Kontakty z numerami telefonów"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Wyślij SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Wyślij wiadomość tekstową"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Zadzwoń do: <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Edytuj numer przed nawiązaniem połączenia"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Dodaj do kontaktów"</string>
@@ -128,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Wyczyść rejestr połączeń"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Rejestr połączeń jest pusty."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"Numer MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Poczta głosowa"</string>
<string name="unknown" msgid="740067747858270469">"Nieznane"</string>
<string name="private_num" msgid="6374339738119166953">"Numer prywatny"</string>
@@ -137,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Wczytywanie z karty SIM…"</string>
<string name="simContacts_title" msgid="27341688347689769">"Kontakty z karty SIM"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Zsynchronizuj kontakty Google!"</font>" "\n"Po zsynchronizowaniu telefonu zawsze będziesz mieć kontakty pod ręką."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Nie masz żadnych kontaktów."\n\n"Aby dodać kontakty, wybierz "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" i wybierz polecenie:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Nowy kontakt"</b></font>" w celu utworzenia nowego kontaktu od początku"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importuj kontakty"</b></font>" w celu dodania kontaktów z karty SIM"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Nie masz żadnych kontaktów."\n\n"Aby dodać kontakty, naciśnij "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" i wybierz polecenie:"\n\n" "<li><font fgcolor="#ffffffff"><b>"Synchronizacja grup"</b></font>" w celu dodania kontaktów z nowego lub istniejącego konta Google"\n</li>\n" "<li><font fgcolor="#ffffffff"><b>"Nowy kontakt"</b></font>" w celu utworzenia nowego kontaktu od początku"\n</li>\n" "<li><font fgcolor="#ffffffff"><b>"Importuj kontakty"</b></font>" w celu dodania kontaktów z karty SIM"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Nie masz żadnych kontaktów do wyświetlenia."\n\n"Aby dodać kontakty, naciśnij przycisk "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" i dotknij opcji:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konta"</b></font>", aby dodać lub skonfigurować konto zawierające kontakty, które można synchronizować z telefonem."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nowy kontakt"</b></font>", aby utworzyć nowy kontakt od początku."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importuj/eksportuj"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Nie masz żadnych kontaktów do wyświetlenia. (Jeśli przed chwilą dodano konto, synchronizacja kontaktów może potrwać kilka minut)."\n\n"Aby dodać kontakty, naciśnij przycisk "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" i dotknij opcji:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konta"</b></font>", aby dodać lub skonfigurować konto zawierające kontakty, które można synchronizować z telefonem."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opcje wyświetlania"</b></font>", aby zmienić widoczne typy kontaktów."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nowy kontakt"</b></font>", aby utworzyć nowy kontakt od początku."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importuj/eksportuj"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Nie masz żadnych kontaktów do wyświetlenia."\n\n"Aby dodać kontakty, naciśnij przycisk "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" i dotknij opcji:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konta"</b></font>", aby dodać lub skonfigurować konto zawierające kontakty, które można synchronizować z telefonem."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nowy kontakt"</b></font>", aby utworzyć nowy kontakt od początku."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importuj/eksportuj"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Nie masz żadnych kontaktów do wyświetlenia. (Jeśli przed chwilą dodano konto, synchronizacja kontaktów może potrwać kilka minut)."\n\n"Aby dodać kontakty, naciśnij przycisk "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" i dotknij opcji:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konta"</b></font>", aby dodać lub skonfigurować konto zawierające kontakty, które można synchronizować z telefonem."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opcje wyświetlania"</b></font>", aby zmienić widoczne typy kontaktów."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nowy kontakt"</b></font>", aby utworzyć nowy kontakt od początku."\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importuj/eksportuj"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Nie masz żadnych ulubionych kontaktów."\n\n"Aby dodać kontakt do listy ulubionych:"\n\n" "<li>"Dotknij karty "<b>"Kontakty"</b>"."\n</li>" "\n<li>"Dotknij kontaktu, który chcesz dodać do ulubionych."\n</li>" "\n<li>"Dotknij ikony gwiazdki obok nazwy kontaktu."\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Wybierz grupy do zsynchronizowania"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Wszystkie kontakty"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Wszystkie kontakty"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Oznaczone gwiazdką"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Telefony"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Użyj klawiatury tonowej"</string>
@@ -171,8 +232,9 @@
<string name="returnCall" msgid="8171961914203617813">"Połączenie zwrotne"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> min <xliff:g id="SECONDS">%s</xliff:g> sek."</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Częste połączenia"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Dodaj kontakt"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Dodaj kontakt"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Czy dodać adres „<xliff:g id="EMAIL">%s</xliff:g>” do kontaktów?"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Wszystkie"</string>
<string name="description_image_button_one" msgid="1740638037139856139">"jeden"</string>
<string name="description_image_button_two" msgid="5882638439003731308">"dwa"</string>
<string name="description_image_button_three" msgid="8709731759376015180">"trzy"</string>
@@ -185,43 +247,176 @@
<string name="description_image_button_star" msgid="3365919907520767866">"gwiazdka"</string>
<string name="description_image_button_zero" msgid="4133108949401820710">"zero"</string>
<string name="description_image_button_pound" msgid="3039765597595889230">"funt"</string>
- <string name="no_sdcard_title" msgid="6455416795090113715">"Brak karty SD"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Nie wykryto karty SD"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Wyszukiwanie danych VCard"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Brak karty SD"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Nie wykryto karty SD"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Wyszukiwanie danych vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Skąd chcesz zaimportować kontakty?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"Karta SIM"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"Karta SD"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importuj wszystkie pliki VCard"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Zaimportuj jeden plik VCard"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Wyszukiwanie danych VCard w pliku VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Skanowanie karty SD nie powiodło się"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Skanowanie karty SD nie powiodło się"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importuj z karty SIM"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importuj z karty SD"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Eksportuj na kartę SD"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importuj jeden plik vCard"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importuj wiele plików vCard"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importuj wszystkie pliki vCard"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Wyszukiwanie danych vCard na karcie SD"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Skanowanie karty SD nie powiodło się"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Skanowanie karty SD nie powiodło się (przyczyna: „<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Błąd wejścia/wyjścia"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Analiza danych VCard nie powiodła się"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Na karcie SD nie znaleziono żadnego pliku VCard"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"W wybranym zakresie nie znaleziono poprawnej pozycji VCard"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Wybierz plik VCard"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Wybierz plik VCard do zaimportowania"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Odczytywanie danych VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Odczytywanie plików VCard"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Importowanie danych VCard"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Odczytywanie danych VCard nie powiodło się"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"Nie można odczytać danych VCard"\n"Przyczyna niepowodzenia: „<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Nie można zanalizować pliku vCard z nieoczekiwanego powodu"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Nie można zanalizować pliku vCard, mimo że prawdopodobnie ma on prawidłowy format. Bieżąca wersja go nie obsługuje."</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Na karcie SD nie znaleziono żadnego pliku vCard"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"W wybranym zakresie nie znaleziono prawidłowego wpisu vCard"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Nie można zaimportować co najmniej jednego pliku (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Nieznany błąd"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Wybierz plik vCard"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Wybierz plik vCard do zaimportowania"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Odczytywanie danych vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Odczytywanie plików vCard"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Importowanie danych vCard"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Odczytywanie danych vCard nie powiodło się"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Nie można odczytać danych vCard."\n"Przyczyna niepowodzenia: „<xliff:g id="FAIL_REASON">%s</xliff:g>”."</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"Kontakt <xliff:g id="CURRENT_NUMBER">%s</xliff:g> z <xliff:g id="TOTAL_NUMBER">%s</xliff:g>"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"plik <xliff:g id="CURRENT_NUMBER">%s</xliff:g> z <xliff:g id="TOTAL_NUMBER">%s</xliff:g>"</string>
+ <string name="export_all_contacts" msgid="2873892623335194071">"Wszystkie kontakty"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Kontakty przechowywane lokalnie"</string>
<string name="export_contact_list" msgid="3165097742175874384">"Eksportuj kontakty"</string>
- <string name="confirm_export_title" msgid="1693047909433122854">"Potwierdzenie eksportowania"</string>
- <string name="confirm_export_message" msgid="63482084706768079">"Czy chcesz wyeksportować swoją listę kontaktów do pliku „<xliff:g id="VCARD_FILENAME">%s</xliff:g>”?"</string>
- <string name="exporting_contact_failed_title" msgid="1455264422455075858">"Eksportowanie danych kontaktowych nie powiodło się"</string>
- <string name="exporting_contact_failed_message" msgid="1426451081541603512">"Eksportowanie danych kontaktowych nie powiodło się"\n"Przyczyna niepowodzenia: „<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
- <string name="fail_reason_too_many_vcard" msgid="5416992255233341607">"Zbyt dużo danych VCard na karcie SD"</string>
- <string name="fail_reason_too_long_filename" msgid="7105223965196949065">"Wymagana jest zbyt długa nazwa pliku („<xliff:g id="FILENAME">%s</xliff:g>”)"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Potwierdź eksport"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Czy na pewno chcesz wyeksportować listę kontaktów do pliku „<xliff:g id="VCARD_FILENAME">%s</xliff:g>”?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Nie można wyeksportować danych kontaktu"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Nie można wyeksportować danych kontaktu."\n"Przyczyna niepowodzenia: „<xliff:g id="FAIL_REASON">%s</xliff:g>”."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Brak kontaktów, które można wyeksportować"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Zbyt dużo plików vCard na karcie SD"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Wymagana nazwa pliku jest zbyt długa („<xliff:g id="FILENAME">%s</xliff:g>”)"</string>
<string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Nie można otworzyć lub utworzyć katalogu docelowego „<xliff:g id="DIR_NAME">%s</xliff:g>”"</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"Eksportowanie danych kontaktowych"</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"Eksportowanie danych kontaktowych do pliku „<xliff:g id="FILE_NAME">%s</xliff:g>”"</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Nie można zainicjować programu eksportującego: „<xliff:g id="EXACT_REASON">%s</xliff:g>”"</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Wystąpił błąd podczas eksportowania: „<xliff:g id="EXACT_REASON">%s</xliff:g>”"</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Nie można pobrać informacji o bazie danych"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Brak kontaktów, które można wyeksportować. Być może wybrano dane, których nie można eksportować."</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"Obiekt tworzenia danych vCard nie został poprawnie zainicjowany"</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Nie można otworzyć pliku „<xliff:g id="FILE_NAME">%s</xliff:g>”: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"Kontakt <xliff:g id="CURRENT_NUMBER">%s</xliff:g> z <xliff:g id="TOTAL_NUMBER">%s</xliff:g>"</string>
<string name="search_settings_description" msgid="2675223022992445813">"Imiona i nazwiska oraz nazwy w Twoich kontaktach"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Dodaj 2-sekundową pauzę"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Dodaj oczekiwanie"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Wybierz numer"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Zadzwoń przy użyciu"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Wyślij SMS przy użyciu"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Zapamiętaj ten wybór"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Nie znaleziono aplikacji do obsługi tej akcji"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Zapamiętaj ten wybór"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Nieznane"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Konta"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importuj/eksportuj"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importuj/eksportuj kontakty"</string>
+ <string name="menu_share" msgid="943789700636542260">"Udostępnij"</string>
+ <string name="share_via" msgid="563121028023030093">"Udostępnij kontakt za pośrednictwem"</string>
+ <string name="share_error" msgid="4374508848981697170">"Tego kontaktu nie można udostępniać."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nazwa"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Pseudonim"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizacja"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Adres witryny"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Wydarzenie"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"D"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"K"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"S"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"I"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Ten kontakt jest tylko do odczytu"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Więcej"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Nazwa główna"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Utwórz kontakt na koncie"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Usuń grupę synchronizacji"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Dodaj grupę synchronizacji"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Więcej grup..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Wszystkie inne kontakty"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Wszystkie kontakty"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Usunięcie grupy „<xliff:g id="GROUP">%s</xliff:g>” z ustawień synchronizacji spowoduje również usunięcie wszelkich rozgrupowanych kontaktów z tych ustawień."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Tylko telefon (brak synchronizacji)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Nazwa wyświetlana"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Telefon – <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Telefon – domowy"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Telefon – komórkowy"</string>
+ <string name="call_work" msgid="5328785911463744028">"Telefon – służbowy"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Telefon – faks służbowy"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Telefon – faks domowy"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Telefon – pager"</string>
+ <string name="call_other" msgid="5605584621798108205">"Telefon – inny"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Zadzwoń – połączenie zwrotne"</string>
+ <string name="call_car" msgid="3280537320306436445">"Telefon – samochód"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Telefon – firmowy główny"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Zadzwoń – ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Zadzwoń pod nr główny"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Połącz – inny faks"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Telefon – radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Połącz – teleks"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Zadzwoń – TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Zadzwoń – służbowy komórkowy"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Zadzwoń – pager służbowy"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Zadzwoń – <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Telefon – wiadomość MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Tekst – <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Tekst – domowy"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Tekst – komórkowy"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Tekst – służbowy"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Tekst – faks służbowy"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Tekst – faks domowy"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Tekst – pager"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Tekst – inny"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"SMS – numer zwrotny"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Tekst – samochód"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Tekst – firmowy główny"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"SMS – ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"SMS – nr główny"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"SMS – inny faks"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Tekst – radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"SMS – teleks"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"SMS – TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"SMS – służbowy komórkowy"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"SMS – pager służbowy"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"SMS – <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Tekst – wiadomość MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"Adres e-mail – domowy"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Adres e-mail – komórkowy"</string>
+ <string name="email_work" msgid="2807430017302722689">"Adres e-mail – służbowy"</string>
+ <string name="email_other" msgid="8093933498541795832">"Adres e-mail – inny"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Adres e-mail – <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Adres e-mail"</string>
+ <string name="map_home" msgid="1243547733423343982">"Wyświetl adres domowy"</string>
+ <string name="map_work" msgid="1360474076921878088">"Wyświetl adres służbowy"</string>
+ <string name="map_other" msgid="5560707927535653892">"Wyświetl inny adres"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Wyświetl adres: <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Czat w AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Czat w Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Czat w Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Czat w Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Czat w QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Czat w Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Czat w ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Czat w Jabberze"</string>
+ <string name="chat" msgid="9025361898797412245">"Czat"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Ulica"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Skrytka pocztowa"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Okolica"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Miasto"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Województwo"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Kod pocztowy"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Kraj"</string>
+ <string name="name_given" msgid="1687286314106019813">"Imię"</string>
+ <string name="name_family" msgid="3416695586119999058">"Nazwisko"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Przedrostek nazwiska"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Drugie imię"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Przyrostek nazwiska"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Imię (fonetycznie)"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Drugie imię (fonetycznie)"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Nazwisko (fonetycznie)"</string>
+ <string name="split_label" msgid="8262112659919449087">"Podziel"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Utwórz dla tych danych osobny kontakt."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Z konta <xliff:g id="SOURCE">%1$s</xliff:g>: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"Kontakt <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="from_account_format" msgid="687567483928582084">"z <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Użyj tego zdjęcia"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"W tym urządzeniu nie można edytować informacji kontaktowych <xliff:g id="SOURCE">%1$s</xliff:g>."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Brak dodatkowych informacji dla tego kontaktu"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 2b730bf..ae35da1 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -16,18 +16,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Contactos"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Telefone"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefone"</string>
<string name="shortcutContact" msgid="749243779392912958">"Contacto"</string>
- <!-- no translation found for shortcutDialContact (7165340343023469996) -->
- <skip />
- <!-- no translation found for shortcutMessageContact (3025782962770298900) -->
- <skip />
- <!-- no translation found for shortcutActivityTitle (6642877210643565436) -->
- <skip />
- <!-- no translation found for callShortcutActivityTitle (6065749861423648991) -->
- <skip />
- <!-- no translation found for messageShortcutActivityTitle (3084542316620335911) -->
- <skip />
+ <string name="shortcutDialContact" msgid="746622101599186779">"Marcação directa"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Mensagem directa"</string>
+ <string name="shortcutActivityTitle" msgid="6642877210643565436">"Seleccionar um atalho de contacto"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"Seleccionar um número a marcar"</string>
+ <string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Seleccionar um número para enviar mensagem"</string>
<string name="starredList" msgid="4817256136413959463">"Marcado com estrela"</string>
<string name="frequentList" msgid="7154768136473953056">"Frequentes"</string>
<string name="strequentList" msgid="5640192862059373511">"Favoritos"</string>
@@ -45,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Mostrar código de barras"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Editar contacto"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Eliminar contacto"</string>
- <string name="menu_call" msgid="7359207953236681606">"Chamada"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Enviar SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Ligar para contacto"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Enviar SMS/MMS para contacto"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Enviar e-mail"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Endereço no mapa"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Utilizar como número predefinido"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Predefinir e-mail"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Separar"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Separar contacto"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Contactos separados"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Separar contacto"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Tem a certeza de que quer separar este contacto único em vários contactos: um para cada conjunto de informações de contacto que lhe foi agregado?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Associar"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Mostrar origens"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Ocultar origens"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Associar contacto"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Associar contactos"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Seleccione o contacto que pretende associar a <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Mostrar todos os contactos"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Contactos sugeridos"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Todos os contactos"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Contactos associados"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Opções"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Opções"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Eliminar"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Não pode eliminar contactos de contas só de leitura, mas pode ocultá-los nas suas listas de contactos."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Este contacto contém informações de várias contas. As informações de contas só de leitura serão ocultadas nas suas listas de contactos, mas não eliminadas."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"A eliminação deste contacto eliminará informações de várias contas."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Este contacto será eliminado."</string>
<string name="menu_done" msgid="796017761764190697">"Concluído"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Reverter"</string>
@@ -60,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonético"</string>
<string name="label_notes" msgid="8337354953278341042">"Notas"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Toque"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Grupos"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Editar grupos"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Primeiro e último"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Nome fonético"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
@@ -69,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Número de telefone"</string>
<string name="ghostData_email" msgid="6184537075551565919">"Endereço de e-mail"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Endereço postal"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Mostrar grupo"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"O contacto não existe."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Criar novo contacto"</string>
<string name="selectLabel" msgid="4255424123394910733">"Seleccionar etiqueta"</string>
@@ -85,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Não existem imagens disponíveis no telefone."</string>
<string name="attachToContact" msgid="8820530304406066714">"Ícone de contacto"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Nome da etiqueta personalizada"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Mostrar grupos"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Opções de visualização"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Opções de visualização"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Editar grupos sincronizados"</string>
<string name="importFromSim" msgid="8383900146531125319">"Importar contactos"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Enviar as chamadas directamente para o correio de voz"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"As chamadas são enviadas directamente para o correio de voz."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Predefinido"</string>
<string name="addPicture" msgid="1594679312161537678">"Adicionar ícone"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Alterar ícone"</string>
<string name="removePicture" msgid="3041230993155966350">"Remover ícone"</string>
<string name="noContacts" msgid="8579310973261953559">"Sem contactos."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Não foram encontrados contactos correspondentes."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Sem contactos com números de telefone."</string>
<string name="noFavorites" msgid="812766386743315815">"Sem favoritos."</string>
<string name="select_group_title" msgid="7955698611959835612">"Grupos"</string>
<string name="groupEmpty" msgid="6661950109828194595">"O seu grupo \"<xliff:g id="GROUPNAME">%s</xliff:g>\" está vazio."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Todos os contactos"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Apenas contactos com telefones"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Apresentar apenas contactos que tenham números de telefone"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Escolher contactos a apresentar"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> contactos"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> contactos, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> com telefone"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Sincronizar todos os contactos"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Os meus contactos"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Os meus contactos"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Contactos com números de telefone"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Marcado com estrela no Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"A guardar contacto..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"A guardar opções de visualização..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Contacto criado."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Contacto guardado."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Erro, impossível guardar alterações do contacto."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Marcar número"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Números de telefone"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Enviar SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Enviar texto"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Enviar e-mail"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"Endereços de e-mail"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Enviar mensagem instantânea"</string>
@@ -115,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Endereço no mapa"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Endereços postais"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organizações"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Grupos"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Outras informações"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Outras opções"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Mais"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"1 contacto com número de telefone"</item>
+ <item quantity="other" msgid="6133262880804110289">"<xliff:g id="COUNT">%d</xliff:g> contactos com números de telefone"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Sem contactos visíveis com números de telefone"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"1 contacto"</item>
+ <item quantity="other" msgid="2865867557378939630">"<xliff:g id="COUNT">%d</xliff:g> contactos"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Sem contactos visíveis"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"Foi encontrado 1 contacto"</item>
+ <item quantity="other" msgid="7752927996850263152">"Foram encontrados <xliff:g id="COUNT">%d</xliff:g> contactos"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Contacto não encontrado"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Social"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contactos"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Marcador"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefone"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Registo de chamadas"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Todos os contactos"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Contactos marcados com estrela"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Contactos com números de telefone"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Enviar mensagem SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Enviar mensagem de texto"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Telefonar a <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Editar número antes de efectuar a chamada"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Adicionar aos contactos"</string>
@@ -133,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Limpar registo de chamadas"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"O registo de chamadas está vazio."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Correio de voz"</string>
<string name="unknown" msgid="740067747858270469">"Desconhecido"</string>
<string name="private_num" msgid="6374339738119166953">"Número particular"</string>
@@ -142,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"A carregar a partir do cartão SIM..."</string>
<string name="simContacts_title" msgid="27341688347689769">"Contactos no cartão SIM"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Sincronize os seus contactos do Google!"</font>" "\n"Depois de efectuar a sincronização para o seu telefone, os seus contactos ficarão disponíveis onde quer que esteja."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Não tem contactos."\n\n"Para adicionar contactos, prima "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e seleccione:"\n\n<li><font fgcolor="#ffffffff"><b>"Novo contacto"</b></font>" para criar um novo contacto desde o princípio"\n</li>"."\n<li><font fgcolor="#ffffffff"><b>"Importar contactos"</b></font>" para adicionar contactos a partir do cartão SIM"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Não tem nenhum contacto."\n\n"Para adicionar contactos, prima "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e seleccione:"\n\n<li><font fgcolor="#ffffffff"><b>"Editar grupos sincronizados"</b></font>" para adicionar a partir de uma Conta Google nova ou já existente"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Novo contacto"</b></font>" para criar um novo contacto desde o início"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar contactos"</b></font>" para adicionar contactos a partir do cartão SIM"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Não tem contactos para apresentar."\n\n"Para adicionar contactos, prima "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e toque em:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Contas"</b></font>" para adicionar ou configurar uma conta com contactos que pode sincronizar no telefone"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Novo contacto"</b></font>" para criar um novo contacto de raiz"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Não tem contactos para apresentar (se acabou de adicionar uma conta, pode demorar alguns minutos a sincronizar os contactos)."\n\n"Para adicionar contactos, prima "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e toque em:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Contas"</b></font>" para adicionar ou configurar uma conta com os contactos que pode sincronizar no telefone"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opções de visualização"</b></font>" para alterar os contactos visíveis"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Novo contacto"</b></font>" para criar uma nova conta de raiz"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Não tem contactos para apresentar."\n\n"Para adicionar contactos, prima "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e toque em:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Contas"</b></font>" para adicionar ou configurar uma conta com contactos que pode sincronizar no telefone"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Novo contacto"</b></font>" para criar um novo contacto de raiz"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Não tem contactos para apresentar (se acabou de adicionar uma conta, pode demorar alguns minutos a sincronizar os contactos)."\n\n"Para adicionar contactos, prima "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e toque em:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Contas"</b></font>" para adicionar ou configurar uma conta com os contactos que pode sincronizar no telefone"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opções de visualização"</b></font>" para alterar os contactos visíveis"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Novo contacto"</b></font>" para criar uma nova conta de raiz"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Não tem favoritos."\n\n"Para adicionar um contacto à sua lista de favoritos:"\n\n" "<li>"Toque no separador "<b>"Contactos"</b>" "\n</li>" "\n<li>"Toque no contacto que pretende adicionar aos favoritos"\n</li>" "\n<li>"Toque na estrela junto ao nome do contacto"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Seleccionar grupos para sincronizar"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Todos os contactos"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Todos os contactos"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Marcado com estrela"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Telefones"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Utilizar teclado numérico com tons de toque"</string>
@@ -176,84 +232,191 @@
<string name="returnCall" msgid="8171961914203617813">"Devolver chamada"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> min <xliff:g id="SECONDS">%s</xliff:g> seg"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Números de marcação frequente"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Adicionar contacto"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Adicionar contacto"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Adicionar \"<xliff:g id="EMAIL">%s</xliff:g>\" aos contactos?"</string>
- <!-- no translation found for description_image_button_one (1740638037139856139) -->
- <skip />
- <!-- no translation found for description_image_button_two (5882638439003731308) -->
- <skip />
- <!-- no translation found for description_image_button_three (8709731759376015180) -->
- <skip />
- <!-- no translation found for description_image_button_four (3530239685642246130) -->
- <skip />
- <!-- no translation found for description_image_button_five (1182465427501188413) -->
- <skip />
- <!-- no translation found for description_image_button_six (2093656269261415475) -->
- <skip />
- <!-- no translation found for description_image_button_seven (2450357020447676481) -->
- <skip />
- <!-- no translation found for description_image_button_eight (6969435115163287801) -->
- <skip />
- <!-- no translation found for description_image_button_nine (7857248695662558323) -->
- <skip />
- <!-- no translation found for description_image_button_star (3365919907520767866) -->
- <skip />
- <!-- no translation found for description_image_button_zero (4133108949401820710) -->
- <skip />
- <!-- no translation found for description_image_button_pound (3039765597595889230) -->
- <skip />
- <string name="no_sdcard_title" msgid="6455416795090113715">"Sem cartão SD"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Não foi detectado nenhum cartão SD"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"A procurar VCard"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Todos"</string>
+ <string name="description_image_button_one" msgid="1740638037139856139">"um"</string>
+ <string name="description_image_button_two" msgid="5882638439003731308">"dois"</string>
+ <string name="description_image_button_three" msgid="8709731759376015180">"três"</string>
+ <string name="description_image_button_four" msgid="3530239685642246130">"quatro"</string>
+ <string name="description_image_button_five" msgid="1182465427501188413">"cinco"</string>
+ <string name="description_image_button_six" msgid="2093656269261415475">"seis"</string>
+ <string name="description_image_button_seven" msgid="2450357020447676481">"sete"</string>
+ <string name="description_image_button_eight" msgid="6969435115163287801">"oito"</string>
+ <string name="description_image_button_nine" msgid="7857248695662558323">"nove"</string>
+ <string name="description_image_button_star" msgid="3365919907520767866">"estrela"</string>
+ <string name="description_image_button_zero" msgid="4133108949401820710">"zero"</string>
+ <string name="description_image_button_pound" msgid="3039765597595889230">"libra"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Nenhum cartão SD"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Não foi detectado nenhum cartão SD"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"A procurar vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"De onde pretende importar contactos?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"Cartão SIM"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"Cartão SD"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importar todos os ficheiros VCard"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Importar um ficheiro VCard"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"A procurar dados VCard no VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Falha na análise do cartão SD"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Falha na análise do cartão SD"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importar do cartão SIM"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importar do cartão SD"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Exportar para cartão SD"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importar um ficheiro VCard"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importar vários ficheiros vCard"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importar todos os ficheiros VCard"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Procurar dados do vCard no cartão SD"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Falha na análise do cartão SD"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Falha na análise do cartão SD (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Erro de E/S"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Falha na análise do VCard"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Não foi encontrado nenhum ficheiro VCard no cartão SD"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Não foi encontrada nenhuma entrada VCard válida para a sua selecção"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Seleccionar ficheiro VCard"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Seleccione um ficheiro VCard para importar"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"A ler VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"A ler ficheiro(s) VCard"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"A importar dados VCard"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Falha na leitura de dados VCard"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"Não foi possível ler os dados VCard"\n"Motivo da falha: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Falha na análise do vCard por motivo inesperado"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Falha na análise do vCard embora o formato pareça válido, uma vez que não é suportado pela implementação actual"</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Não foi encontrado nenhum ficheiro vCard no cartão SD"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Não foi encontrada nenhuma entrada vCard válida para a sua selecção"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"A importação de um ou vários ficheiros falhou (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Erro desconhecido"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Seleccionar ficheiro vCard"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Seleccione um ficheiro vCard para importar"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"A ler vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"A ler ficheiro(s) vCard"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"A importar dados do vCard"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Falha na leitura de dados do vCard"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Não foi possível ler o vCard."\n"Motivo da falha: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contactos"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> ficheiros"</string>
- <!-- no translation found for export_contact_list (3165097742175874384) -->
- <skip />
- <!-- no translation found for confirm_export_title (1693047909433122854) -->
- <skip />
- <!-- no translation found for confirm_export_message (63482084706768079) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_title (1455264422455075858) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_message (1426451081541603512) -->
- <skip />
- <!-- no translation found for fail_reason_too_many_vcard (5416992255233341607) -->
- <skip />
- <!-- no translation found for fail_reason_too_long_filename (7105223965196949065) -->
- <skip />
- <!-- no translation found for fail_reason_cannot_open_destination_dir (1739293936432987758) -->
- <skip />
- <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
- <skip />
- <!-- no translation found for exporting_contact_list_message (5640326540405486055) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_initialize_exporter (4943708332700987376) -->
- <skip />
- <!-- no translation found for fail_reason_error_occurred_during_export (2151165129433831202) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_open_file (4013520943128739511) -->
- <skip />
- <!-- no translation found for exporting_contact_list_progress (560522409559101193) -->
- <skip />
- <!-- no translation found for search_settings_description (2675223022992445813) -->
- <skip />
+ <string name="export_all_contacts" msgid="2873892623335194071">"Todos os contactos"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Contactos armazenados localmente"</string>
+ <string name="export_contact_list" msgid="3165097742175874384">"Exportar contactos"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Confirmar exportação"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Tem a certeza de que pretende exportar a lista de contactos para \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\"?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Falha ao exportar dados de contacto"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Falha na exportação de dados de contacto."\n"Motivo da falha: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Não existe um contacto exportável"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Demasiados ficheiros vCard no cartão SD"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Nome de ficheiro demasiado longo (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Não é possível abrir ou criar o directório de destino \"<xliff:g id="DIR_NAME">%s</xliff:g>\""</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportar dados do contacto"</string>
+ <string name="exporting_contact_list_message" msgid="5640326540405486055">"Exportar dados do contacto para \"<xliff:g id="FILE_NAME">%s</xliff:g>\""</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Não foi possível iniciar o exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Erro ocorrido durante a exportação: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Falha na obtenção de informações da base de dados"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Não existe nenhum contacto exportável. Pode ter escolhido dados não exportáveis"</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"O compositor vCard não foi inicializado correctamente"</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Não foi possível abrir \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contactos"</string>
+ <string name="search_settings_description" msgid="2675223022992445813">"Nomes dos contactos"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Adicionar pausa de 2 seg."</string>
+ <string name="add_wait" msgid="3360818652790319634">"Adicionar espera"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Marcar"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Ligar utilizando"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Enviar SMS utilizando"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Memorizar esta escolha"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Não foram encontradas aplicações para executar esta acção"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Memorizar esta escolha"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Desconhecido"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Contas"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importar/Exportar"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importar/Exportar contactos"</string>
+ <string name="menu_share" msgid="943789700636542260">"Partilhar"</string>
+ <string name="share_via" msgid="563121028023030093">"Partilhar contacto através de"</string>
+ <string name="share_error" msgid="4374508848981697170">"Não é possível partilhar este contacto."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nome"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Alcunha"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organização"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Web site"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Evento"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"R"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"T"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"E"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"O"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Este contacto é apenas de leitura"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Mais"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Nome principal"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Criar contacto subordinado à conta"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Remover grupo de sincronização"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Adicionar grupo de sincronização"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Mais grupos..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Todos os outros contactos"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Todos os contactos"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Ao remover \"<xliff:g id="GROUP">%s</xliff:g>\" da sincronização, removerá também quaisquer contactos não agrupados."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Apenas telefone (não sincronizado)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Nome a apresentar"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Ligar para <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Ligar para residência"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Ligar para telemóvel"</string>
+ <string name="call_work" msgid="5328785911463744028">"Ligar para emprego"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Ligar para fax do emprego"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Ligar para o fax da residência"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Ligar para pager"</string>
+ <string name="call_other" msgid="5605584621798108205">"Ligar para outros"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Ligar para rechamada"</string>
+ <string name="call_car" msgid="3280537320306436445">"Ligar para automóvel"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Ligar para telefone principal da empresa"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Ligar para RDIS"</string>
+ <string name="call_main" msgid="6082900571803441339">"Ligar para telefone principal"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Ligar para outro fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Ligar para rádio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Ligar para telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Ligar para telefone TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Ligar para telemóvel do emprego"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Ligar para pager do emprego"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Ligar a <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Ligar MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Enviar SMS a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Enviar SMS para residência"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Enviar SMS para telemóvel"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Enviar SMS para emprego"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Enviar SMS para fax do emprego"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Enviar SMS para fax da residência"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Enviar SMS para pager"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Enviar SMS para outros"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Enviar SMS de resposta"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Enviar SMS para automóvel"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Enviar SMS para telefone principal da empresa"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"SMS para RDIS"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Enviar SMS para telefone principal"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Enviar SMS para outro fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Enviar SMS para rádio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Enviar SMS para telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Enviar SMS para telefone TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Enviar SMS para telemóvel do emprego"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Enviar SMS para pager do emprego"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Enviar SMS para <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Enviar MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"Enviar e-mail para residência"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Enviar e-mail para telemóvel"</string>
+ <string name="email_work" msgid="2807430017302722689">"Enviar e-mail para emprego"</string>
+ <string name="email_other" msgid="8093933498541795832">"Enviar e-mail para outro"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Enviar e-mail a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-mail"</string>
+ <string name="map_home" msgid="1243547733423343982">"Ver endereço da residência"</string>
+ <string name="map_work" msgid="1360474076921878088">"Ver endereço do emprego"</string>
+ <string name="map_other" msgid="5560707927535653892">"Ver outros endereços"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Ver endereço de <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chat utilizando AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chat utilizando Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chat utilizando Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chat utilizando Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chat utilizando QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chat através do Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chat utilizando ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chat utilizando Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Rua"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Apartado"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Vizinhança"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Cidade"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Região"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Código postal"</string>
+ <string name="postal_country" msgid="7638264508416368690">"País"</string>
+ <string name="name_given" msgid="1687286314106019813">"Segundo nome"</string>
+ <string name="name_family" msgid="3416695586119999058">"Segundo apelido"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Título académico ou profissional"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Primeiro apelido"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Título honorífico ou eclesiástico"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Fonética do segundo nome"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonética do primeiro apelido"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Fonética do segundo apelido"</string>
+ <string name="split_label" msgid="8262112659919449087">"Separar"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Fazer destes dados o seu próprio contacto."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Da conta <xliff:g id="SOURCE">%1$s</xliff:g>: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"Contacto de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Utilizar esta fotografia"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"Não é possível editar as informações de contacto do <xliff:g id="SOURCE">%1$s</xliff:g> neste dispositivo."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Não há informações adicionais para este contacto"</string>
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index d310910..9bb4911 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -16,18 +16,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Contatos"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Discador"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefone"</string>
<string name="shortcutContact" msgid="749243779392912958">"Contato"</string>
- <!-- no translation found for shortcutDialContact (7165340343023469996) -->
- <skip />
- <!-- no translation found for shortcutMessageContact (3025782962770298900) -->
- <skip />
- <!-- no translation found for shortcutActivityTitle (6642877210643565436) -->
- <skip />
- <!-- no translation found for callShortcutActivityTitle (6065749861423648991) -->
- <skip />
- <!-- no translation found for messageShortcutActivityTitle (3084542316620335911) -->
- <skip />
+ <string name="shortcutDialContact" msgid="746622101599186779">"Discagem direta"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Mensagem direta"</string>
+ <string name="shortcutActivityTitle" msgid="6642877210643565436">"Escolha o atalho para um contato"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"Escolha um número a ser chamado"</string>
+ <string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Escolha um número para enviar uma mensagem"</string>
<string name="starredList" msgid="4817256136413959463">"Com estrela"</string>
<string name="frequentList" msgid="7154768136473953056">"Frequente"</string>
<string name="strequentList" msgid="5640192862059373511">"Favoritos"</string>
@@ -45,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Mostrar código de barras"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Editar contato"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Excluir contato"</string>
- <string name="menu_call" msgid="7359207953236681606">"Chamar"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Enviar SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Chamar contato"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Enviar mensagem de texto para o contato"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Enviar e-mail"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Endereço no mapa"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Criar número padrão"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Tornar o e-mail padrão"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Separar"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Dividir contato"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Contatos separados"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Separar contato"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Tem certeza de que deseja separar este único contato em diversos contatos, um para cada conjunto de informações de contato unificado?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Participar"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Mostrar fontes"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Ocultar fontes"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Integrar contato"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Unir contatos"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Selecione o contato que deseja mesclar com <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Mostrar todos os contatos"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Contatos sugeridos"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Todos os contatos"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Contatos unificados"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Opções"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Opções"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Excluir"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Não é possível excluir os contatos das contas somente de leitura, mas você pode ocultá-los nas suas listas de contatos."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Este contato contém informações de diversas contas. As informações de contas somente de leitura ficarão ocultas nas suas listas de contatos, mas não serão excluídas."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Excluir este contato irá excluir informações de várias contas."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Esse evento será excluído."</string>
<string name="menu_done" msgid="796017761764190697">"Concluído"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Reverter"</string>
@@ -60,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonética"</string>
<string name="label_notes" msgid="8337354953278341042">"Observações"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Toque"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Grupos"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Editar grupos"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Nome e sobrenome"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Nome fonético"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
@@ -69,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Número de telefone"</string>
<string name="ghostData_email" msgid="6184537075551565919">"Endereço de e-mail"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Endereço postal"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Exibir grupo"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"O contato não existe."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Criar novo contato"</string>
<string name="selectLabel" msgid="4255424123394910733">"Selecionar marcador"</string>
@@ -85,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Nenhuma imagem disponível no telefone."</string>
<string name="attachToContact" msgid="8820530304406066714">"Ícone de contato"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Personalizar nome do marcador"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Exibir grupo"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Opções de exibição"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Opções de exibição"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Editar grupos sincronizados"</string>
<string name="importFromSim" msgid="8383900146531125319">"Importar contatos"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Enviar chamadas diretamente para o correio de voz"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"As chamadas são enviadas diretamente para o correio de voz."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Padrão"</string>
<string name="addPicture" msgid="1594679312161537678">"Adicionar ícone"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Alterar ícone"</string>
<string name="removePicture" msgid="3041230993155966350">"Remover ícone"</string>
<string name="noContacts" msgid="8579310973261953559">"Nenhum contato."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Nenhum contato correspondente foi encontrado."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Nenhum contato com números de telefone."</string>
<string name="noFavorites" msgid="812766386743315815">"Nenhum favorito"</string>
<string name="select_group_title" msgid="7955698611959835612">"Grupos"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Seu grupo \"<xliff:g id="GROUPNAME">%s</xliff:g>\" está vazio."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Todos os contatos"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Apenas contatos com telefones"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Exibir apenas os contatos com números de telefone"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Escolha os contatos para exibir"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> contatos"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> contatos, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> com telefones"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Sincronizar todos os contatos"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Meus contatos"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Meus contatos"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Contatos com números de telefone"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Com estrela no Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Salvando contato…"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Salvando opções de exibição…"</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Contato criado."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Contato salvo."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Erro: não é possível salvar as alterações do contato."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Discar número"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Números de telefone"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Enviar SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Enviar mensagem de texto"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Enviar e-mail"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"Endereços de e-mail"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Enviar mensagem instantânea"</string>
@@ -115,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Endereço no mapa"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Endereços postais"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organizações"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Grupos"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Outras informações"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Outras opções"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Mais"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Exibindo 1 contato com número de telefone"</item>
+ <item quantity="other" msgid="6133262880804110289">"Exibindo <xliff:g id="COUNT">%d</xliff:g> contatos com números de telefone"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Nenhum contato visível com números de telefone"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Exibindo 1 contato"</item>
+ <item quantity="other" msgid="2865867557378939630">"Exibindo <xliff:g id="COUNT">%d</xliff:g> contatos"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Não há contatos visíveis"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"1 contato encontrado"</item>
+ <item quantity="other" msgid="7752927996850263152">"<xliff:g id="COUNT">%d</xliff:g> contatos encontrados"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Contato não encontrado"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Social"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Contatos"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Discador"</string>
- <string name="recentCallsIconLabel" msgid="1419116422359067949">"Registro de chamadas"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefone"</string>
+ <string name="recentCallsIconLabel" msgid="1419116422359067949">"Chamadas"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Todos os contatos"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Contatos com estrela"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Contatos com números de telefone"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Enviar mensagem SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Enviar mensagem de texto"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Chamar <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Editar número antes da chamada"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Adicionar aos contatos"</string>
@@ -133,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Limpar registro de chamadas"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"O registro de chamadas está vazio."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Correio de voz"</string>
<string name="unknown" msgid="740067747858270469">"Desconhecido"</string>
<string name="private_num" msgid="6374339738119166953">"Número privado"</string>
@@ -142,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Carregando do cartão SIM..."</string>
<string name="simContacts_title" msgid="27341688347689769">"Contatos do cartão SIM"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">" Sincronize seus contatos do Google!"</font>" "\n"Após sincronizar para o seu telefone, seus contatos estarão disponíveis em qualquer lugar que você vá."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Não há nenhum contato."\n\n"Para adicionar contatos, pressione "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e selecione:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Novo contato"</b></font>" para criar um novo contato do início "\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar contatos"</b></font>" para adicionar do seu cartão SIM "\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Não há nenhum contato."\n\n"Para adicionar contatos, pressione "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e selecione:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Editar grupos sincronizados"</b></font>" para adicionar a partir de uma conta do Google nova ou já existente"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Novo contato"</b></font>" para criar um novo contato do início"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar contatos"</b></font>" para adicionar contatos do seu cartão SIM "\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Você não tem nenhum contato para exibir."\n\n"Para adicionar contatos, pressione "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e toque em:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Contas"</b></font>" para adicionar ou configurar uma conta com contatos que possam ser sincronizados com o telefone"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Novo contato"</b></font>" para criar um novo contato do início"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Você não tem contatos para exibir (se acabou de adicionar uma conta, pode levar alguns minutos para sincronizar os contatos.)"\n\n"Para adicionar contatos, pressione"<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e toque em:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Contas"</b></font>" para adicionar ou configurar uma conta com contatos que possam ser sincronizados com o telefone"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opções de exibição"</b></font>" para alterar quais contatos ficam visíveis"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Novo contato"</b></font>" para criar um novo contato do início"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Você não tem nenhum contato para exibir."\n\n"Para adicionar contatos, pressione "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e toque em:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Contas"</b></font>" para adicionar ou configurar uma conta com contatos que possam ser sincronizados com o telefone"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Novo contato"</b></font>" para criar um novo contato do início"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Você não tem contatos para exibir (se acabou de adicionar uma conta, pode levar alguns minutos para sincronizar os contatos.)"\n\n"Para adicionar contatos, pressione"<font fgcolor="#ffffffff"><b>"Menu"</b></font>" e toque em:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Contas"</b></font>" para adicionar ou configurar uma conta com contatos que possam ser sincronizados com o telefone"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Opções de exibição"</b></font>" para alterar quais contatos ficam visíveis"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Novo contato"</b></font>" para criar um novo contato do início"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importar/Exportar"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Você não tem nenhum favorito."\n\n"Para adicionar um contato à sua lista de favoritos:"\n\n" "<li>"Toque na guia "<b>"Contatos"</b>\n</li>" "\n<li>"Toque no contato que deseja adicionar aos seus favoritos"\n</li>" "\n<li>"Toque na estrela ao lado do nome do contato"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Selecionar grupos para sincronizar"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Todos os contatos"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Todos os contatos"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Com estrela"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Telefones"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Usar teclado multifrequencial"</string>
@@ -176,84 +232,191 @@
<string name="returnCall" msgid="8171961914203617813">"Retornar chamada"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> min. <xliff:g id="SECONDS">%s</xliff:g> s"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Frequentemente chamado"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Adicionar contato"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Adicionar contato"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Adicionar \"<xliff:g id="EMAIL">%s</xliff:g>\" aos contatos?"</string>
- <!-- no translation found for description_image_button_one (1740638037139856139) -->
- <skip />
- <!-- no translation found for description_image_button_two (5882638439003731308) -->
- <skip />
- <!-- no translation found for description_image_button_three (8709731759376015180) -->
- <skip />
- <!-- no translation found for description_image_button_four (3530239685642246130) -->
- <skip />
- <!-- no translation found for description_image_button_five (1182465427501188413) -->
- <skip />
- <!-- no translation found for description_image_button_six (2093656269261415475) -->
- <skip />
- <!-- no translation found for description_image_button_seven (2450357020447676481) -->
- <skip />
- <!-- no translation found for description_image_button_eight (6969435115163287801) -->
- <skip />
- <!-- no translation found for description_image_button_nine (7857248695662558323) -->
- <skip />
- <!-- no translation found for description_image_button_star (3365919907520767866) -->
- <skip />
- <!-- no translation found for description_image_button_zero (4133108949401820710) -->
- <skip />
- <!-- no translation found for description_image_button_pound (3039765597595889230) -->
- <skip />
- <string name="no_sdcard_title" msgid="6455416795090113715">"Nenhum Cartão SD disponível"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Nenhum cartão SD detectado"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Pesquisando VCard"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Todos"</string>
+ <string name="description_image_button_one" msgid="1740638037139856139">"um"</string>
+ <string name="description_image_button_two" msgid="5882638439003731308">"dois"</string>
+ <string name="description_image_button_three" msgid="8709731759376015180">"três"</string>
+ <string name="description_image_button_four" msgid="3530239685642246130">"quatro"</string>
+ <string name="description_image_button_five" msgid="1182465427501188413">"cinco"</string>
+ <string name="description_image_button_six" msgid="2093656269261415475">"seis"</string>
+ <string name="description_image_button_seven" msgid="2450357020447676481">"sete"</string>
+ <string name="description_image_button_eight" msgid="6969435115163287801">"oito"</string>
+ <string name="description_image_button_nine" msgid="7857248695662558323">"nove"</string>
+ <string name="description_image_button_star" msgid="3365919907520767866">"estrela"</string>
+ <string name="description_image_button_zero" msgid="4133108949401820710">"zero"</string>
+ <string name="description_image_button_pound" msgid="3039765597595889230">"libra"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Nenhum cartão SD"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Nenhum cartão SD detectado"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Pesquisando vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"De onde você gostaria de importar contatos?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"Cartão SIM"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"Cartão SD"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importar todos os arquivos do VCard"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Importar um arquivo do VCard"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Procurando dados do VCard no VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Falha na verificação do Cartão SD"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Falha na verificação do Cartão SD"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importar do cartão SIM"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importar do cartão SD"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Exportar para cartão SD"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importar um arquivo do vCard"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importar vários arquivos do vCard"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importar todos os arquivos do vCard"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Procurando dados do vCard no cartão SD"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Falha na verificação do cartão SD"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Falha na verificação do cartão SD (Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Erro E/S"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Falha ao analisar o VCard"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Nenhum arquivo de VCard encontrado no Cartão SD"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Nenhuma entrada válida no VCard foi encontrada para sua seleção"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Selecionar arquivo do VCard"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Selecione um arquivo do VCard para importar"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Lendo VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Lendo os arquivos do VCard"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Importando os dados do VCard"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"A leitura dos dados do VCard falhou"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"Não foi possível ler os dados do VCard"\n"Motivo da falha: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Falha ao analisar o vCard por razão inesperada"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Falha ao analisar o vCard. Embora o formato pareça ser válido, a implementação atual não oferece suporte a ele."</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Nenhum arquivo de vCard encontrado no cartão SD"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Nenhuma entrada válida no vCard foi encontrada para a sua seleção"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Falha na importação de um ou mais arquivos (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Erro desconhecido"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Selecionar arquivo do vCard"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Selecione um arquivo do vCard para importar"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Lendo vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Lendo os arquivos do vCard"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Importando os dados do vCard"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"A leitura dos dados do vCard falhou"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Não foi possível ler o vCard."\n"Motivo da falha: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contatos"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> arquivos"</string>
- <!-- no translation found for export_contact_list (3165097742175874384) -->
- <skip />
- <!-- no translation found for confirm_export_title (1693047909433122854) -->
- <skip />
- <!-- no translation found for confirm_export_message (63482084706768079) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_title (1455264422455075858) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_message (1426451081541603512) -->
- <skip />
- <!-- no translation found for fail_reason_too_many_vcard (5416992255233341607) -->
- <skip />
- <!-- no translation found for fail_reason_too_long_filename (7105223965196949065) -->
- <skip />
- <!-- no translation found for fail_reason_cannot_open_destination_dir (1739293936432987758) -->
- <skip />
- <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
- <skip />
- <!-- no translation found for exporting_contact_list_message (5640326540405486055) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_initialize_exporter (4943708332700987376) -->
- <skip />
- <!-- no translation found for fail_reason_error_occurred_during_export (2151165129433831202) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_open_file (4013520943128739511) -->
- <skip />
- <!-- no translation found for exporting_contact_list_progress (560522409559101193) -->
- <skip />
- <!-- no translation found for search_settings_description (2675223022992445813) -->
- <skip />
+ <string name="export_all_contacts" msgid="2873892623335194071">"Todos os contatos"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Contatos armazenados localmente"</string>
+ <string name="export_contact_list" msgid="3165097742175874384">"Exportar contatos"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Confirmar exportação"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Tem certeza de que deseja exportar a sua lista de contatos para \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\"?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Falha ao exportar dados do contato"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Falha ao exportar dados dos contatos."\n"Motivo da falha: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Não há contatos exportáveis"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Muitos arquivos do vCard no cartão SD"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"O nome de arquivo exigido é muito longo (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Não é possível abrir ou criar o diretório de destino \"<xliff:g id="DIR_NAME">%s</xliff:g>\""</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportando dados do contato"</string>
+ <string name="exporting_contact_list_message" msgid="5640326540405486055">"Exportando dados do contato para \"<xliff:g id="FILE_NAME">%s</xliff:g>\""</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Não foi possível iniciar o exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Ocorreu um erro durante a exportação: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Falha ao acessar informações do banco de dados"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Não há contatos exportáveis. Você precisa escolher dados não exportáveis."</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"O vCard não foi iniciado corretamente"</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Não foi possível abrir \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> de <xliff:g id="TOTAL_NUMBER">%s</xliff:g> contatos"</string>
+ <string name="search_settings_description" msgid="2675223022992445813">"Nomes dos seus contatos"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Adicionar pausa de 2 segundos"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Adicionar espera"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Discar"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Chamar usando"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Enviar mensagem de texto usando"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Lembrar desta escolha"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Nenhum aplicativo foi encontrado para executar esta ação."</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Lembrar desta escolha"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Desconhecido"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Contas"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importar/Exportar"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importar/Exportar contatos"</string>
+ <string name="menu_share" msgid="943789700636542260">"Compartilhar"</string>
+ <string name="share_via" msgid="563121028023030093">"Compartilhar contato via"</string>
+ <string name="share_error" msgid="4374508848981697170">"Este contato não pode ser compartilhado."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nome"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Apelido"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organização"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Site"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Evento"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"H"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"W"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"O"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Este contato é apenas leitura"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Mais"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Nome principal"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Criar contato na conta"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Remover sincronização do grupo"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Adicionar grupo sincronizado"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Mais grupos…"</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Todos os outros contatos"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Todos os contatos"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"A remoção de \'<xliff:g id="GROUP">%s</xliff:g>\' da sincronização também removerá todos os contatos não agrupados da sincronização."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Somente telefone (não sincronizado)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Nome de exibição"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Chamar <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Chamar residência"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Chamar celular"</string>
+ <string name="call_work" msgid="5328785911463744028">"Chamar o trabalho"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Chamar fax comercial"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Chamar fax residencial"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Chamar pager"</string>
+ <string name="call_other" msgid="5605584621798108205">"Chamar outros"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Retornar chamada"</string>
+ <string name="call_car" msgid="3280537320306436445">"Chamar carro"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Chamar empresa (principal)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Chamar ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Chamar o principal"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Chamar outro fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Chamar rádio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Chamar telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Chamar TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Chamar celular comercial"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Chamar pager comercial"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Chamar <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Chamar MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Enviar mensagem de texto para <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Enviar mensagem de texto para residência"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Enviar mensagem de texto para celular"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Enviar mensagem de texto para telefone comercial"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Enviar mensagem de texto para o fax comercial"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Enviar mensagem de texto para fax residencial"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Enviar mensagem de texto para o pager"</string>
+ <string name="sms_other" msgid="5131921487474531617">"Enviar mensagem de texto para outras pessoas"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Enviar mensagem de texto para retorno de chamada"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Enviar mensagem de texto para o carro"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Enviar mensagem de texto para empresa (principal)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Mandar mensagem de texto para ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Enviar mensagem de texto para o principal"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Enviar mensagem de texto para outro fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Enviar mensagem de texto para o rádio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Enviar mensagem de texto para telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Enviar mensagem de texto para TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Enviar mensagem de texto para celular comercial"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Enviar mensagem de texto para pager comercial"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Enviar mensagem de texto para <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Enviar texto MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"E-mail (residencial)"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Enviar e-mail para celular"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-mail (comercial)"</string>
+ <string name="email_other" msgid="8093933498541795832">"Enviar e-mail para outras pessoas"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Enviar e-mail para <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-mail"</string>
+ <string name="map_home" msgid="1243547733423343982">"Ver endereço residencial"</string>
+ <string name="map_work" msgid="1360474076921878088">"Ver endereço comercial"</string>
+ <string name="map_other" msgid="5560707927535653892">"Ver outro endereço"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Visualizar endereço de <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Bater papo usando o AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Bater papo usando o Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Bater papo usando o Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Bater papo usando o Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Bater papo usando o QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Bater papo usando o Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Bater papo usando o ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Bater papo usando o Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Bate-papo"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Rua"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Caixa postal"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Vizinhança"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Cidade"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Estado"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"CEP"</string>
+ <string name="postal_country" msgid="7638264508416368690">"País"</string>
+ <string name="name_given" msgid="1687286314106019813">"Nome"</string>
+ <string name="name_family" msgid="3416695586119999058">"Sobrenome"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Prefixo do nome"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Nome do meio"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Sufixo do nome"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Nome fonético"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Nome do meio fonético"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Sobrenome fonético"</string>
+ <string name="split_label" msgid="8262112659919449087">"Dividir"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Transformar esses dados em um contato."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Da conta do <xliff:g id="SOURCE">%1$s</xliff:g>: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"Contato de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="from_account_format" msgid="687567483928582084">"de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Usar esta foto"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"As informações de contato de <xliff:g id="SOURCE">%1$s</xliff:g> não podem ser editadas neste aparelho."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Não há informações adicionais para este contato"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 74e469d..dc18632 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -16,18 +16,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Контакты"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Телефон"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Телефон"</string>
<string name="shortcutContact" msgid="749243779392912958">"Контакт"</string>
- <!-- no translation found for shortcutDialContact (7165340343023469996) -->
- <skip />
- <!-- no translation found for shortcutMessageContact (3025782962770298900) -->
- <skip />
- <!-- no translation found for shortcutActivityTitle (6642877210643565436) -->
- <skip />
- <!-- no translation found for callShortcutActivityTitle (6065749861423648991) -->
- <skip />
- <!-- no translation found for messageShortcutActivityTitle (3084542316620335911) -->
- <skip />
+ <string name="shortcutDialContact" msgid="746622101599186779">"Быстрый звонок"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Быстрое сообщение"</string>
+ <string name="shortcutActivityTitle" msgid="6642877210643565436">"Выбрать контакт для быстрого вызова"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"Выбрать номер для вызова"</string>
+ <string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Выбрать номер для отправки сообщения"</string>
<string name="starredList" msgid="4817256136413959463">"Помеченные"</string>
<string name="frequentList" msgid="7154768136473953056">"Часто вызываемые"</string>
<string name="strequentList" msgid="5640192862059373511">"Избранные"</string>
@@ -45,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Показать штрих-код"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Изменить контакт"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Удалить контакт"</string>
- <string name="menu_call" msgid="7359207953236681606">"Позвонить"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Отправить SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Позвонить"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Отправить SMS/MMS"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Отправить письмо"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Адрес на карте"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Сделать номером по умолчанию"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Установить этот адрес по умолчанию"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Отделить"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Разделить контакт"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Контакты разделены."</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Разделить контакты"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Вы действительно хотите разделить этот контакт на несколько контактов: по одному для каждого набора контактной информации, содержащейся в этом контакте?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Присоединить"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Показать источники"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Скрыть источники"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Присоединить контакт"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Объединить контакты"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Выберите контакт, который нужно объединить с этим адресатом: <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Показать все контакты"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Предлагаемые контакты"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Все контакты"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Контакты присоединились"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Параметры"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Параметры"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Удалить"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Невозможно удалить контакты из аккаунта, доступного только для чтения, однако можно скрыть их в списках контактов."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Этот контакт содержит информацию из различных аккаунтов. Информация из аккаунтов, доступных только для чтения, будет скрыта в ваших списках контактов, но не удалена."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Удаление этого контакта приведет к потере данных из нескольких аккаунтов."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Этот контакт будет удален."</string>
<string name="menu_done" msgid="796017761764190697">"Готово"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Отменить изменения"</string>
@@ -60,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Произношение"</string>
<string name="label_notes" msgid="8337354953278341042">"Примечания"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Мелодия"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Группы"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Изменить группы"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Имя и фамилия"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Произношение имени"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Компания"</string>
@@ -69,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Номер телефона"</string>
<string name="ghostData_email" msgid="6184537075551565919">"Адрес электронной почты"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Почтовый адрес"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Показать группу"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Контакт не существует."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Создать новый контакт"</string>
<string name="selectLabel" msgid="4255424123394910733">"Выбор ярлыка"</string>
@@ -85,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"В телефоне нет картинок."</string>
<string name="attachToContact" msgid="8820530304406066714">"Значок контакта"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Особая метка"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Показать группу"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Варианты отображения"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Варианты отображения"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Изменить группы синхронизации"</string>
<string name="importFromSim" msgid="8383900146531125319">"Импортировать контакты"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Направлять вызовы в голосовую почту"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Звонки направляются в голосовую почту"</string>
<string name="default_ringtone" msgid="9099988849649827972">"По умолчанию"</string>
<string name="addPicture" msgid="1594679312161537678">"Добавить значок"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Изменить значок"</string>
<string name="removePicture" msgid="3041230993155966350">"Удалить значок"</string>
<string name="noContacts" msgid="8579310973261953559">"Нет контактов."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Подходящие контакты не найдены."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Нет контактов с номерами телефонов."</string>
<string name="noFavorites" msgid="812766386743315815">"Нет избранных."</string>
<string name="select_group_title" msgid="7955698611959835612">"Группы"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Группа \"<xliff:g id="GROUPNAME">%s</xliff:g>\" пуста."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Все контакты"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Только контакты с телефонными номерами"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Отображать только контакты, содержащие номера телефонов"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Выберите контакты, которые нужно отображать"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"Контактов: <xliff:g id="COUNT">%0$d</xliff:g>"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"Контактов: <xliff:g id="COUNT_0">%1$d</xliff:g>; с тел. номерами: <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g>"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Синхронизировать все контакты"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Мои контакты"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Мои контакты"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Контакты с номерами телефонов"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Помеченные в Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Контакт сохраняется..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Варианты отображения сохраняются..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Контакт создан."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Контакт сохранен."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Ошибка. Не удалось сохранить изменения контакта."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Набрать номер"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Номера телефонов"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Отправить SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Отправить SMS/MMS"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Отправить письмо"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"Адреса электронной почты"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Отправить мгновенное сообщение"</string>
@@ -115,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Адрес на карте"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Почтовые адреса"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Организации"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Группы"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Другая информация"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Другие параметры"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Добавить"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Показан 1 контакт с номером телефона"</item>
+ <item quantity="other" msgid="6133262880804110289">"Показаны контакты с номерами телефонов: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Нет видимых контактов с номерами телефонов."</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Показан 1 контакт"</item>
+ <item quantity="other" msgid="2865867557378939630">"Показано контактов: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Видимые контакты отсутствуют."</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"Найден 1 контакт"</item>
+ <item quantity="other" msgid="7752927996850263152">"Найдено контактов: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Контакт не найден."</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Социальные"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Контакты"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Избранные"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Телефон"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Кнопки"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Вызовы"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Все контакты"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Помеченные контакты"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Контакты с номерами телефонов"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Отправить SMS-сообщение"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Отправить SMS"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Вызов: <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Изменить номер и вызвать"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Добавить в контакты"</string>
@@ -133,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Очистить список вызовов"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Список вызовов пуст."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Голосовая почта"</string>
<string name="unknown" msgid="740067747858270469">"Неизвестно"</string>
<string name="private_num" msgid="6374339738119166953">"Частный номер"</string>
@@ -142,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Загрузка с SIM-карты…"</string>
<string name="simContacts_title" msgid="27341688347689769">"Контакты на SIM-карте"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Синхронизируйте контакты Google."</font>" "\n"После синхронизации с телефоном ваши контакты будут доступны отовсюду."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"У вас нет контактов."\n\n"Чтобы добавить контакты, нажмите "<font fgcolor="#ffffffff"><b>"Меню"</b></font>" и выберите:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Новый контакт"</b></font>", чтобы создать новый контакт с нуля"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Импортировать контакты"</b></font>", чтобы добавить контакты с SIM-карты"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"У вас нет контактов."\n\n"Чтобы добавить контакты, нажмите "<font fgcolor="#ffffffff"><b>"Меню"</b></font>" и выберите:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Изменить группы синхронизации"</b></font>", чтобы добавить контакт из имеющегося или нового аккаунта Google"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Новый контакт"</b></font>", чтобы создать новый контакт с нуля"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Импортировать контакты"</b></font>", чтобы добавить контакты с SIM-карты"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"У вас нет контактов."\n\n"Чтобы добавить контакты, нажмите "<font fgcolor="#ffffffff"><b>"Меню"</b></font>" и выберите:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Аккаунты"</b></font>", чтобы добавить или настроить аккаунт с контактами, которые можно будет синхронизировать с телефоном;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Новый контакт"</b></font>", чтобы создать контакт \"с нуля\";"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Импорт/Экспорт."</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"У вас нет контактов. (Если вы только что добавили аккаунт, синхронизация контактов может занять несколько минут.)"\n\n"Чтобы добавить контакты, нажмите "<font fgcolor="#ffffffff"><b>"Меню"</b></font>" и выберите:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Аккаунты"</b></font>", чтобы добавить или настроить аккаунт с контактами, которые можно будет синхронизировать с телефоном;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Варианты отображения"</b></font>", чтобы выбрать, какие контакты будут видны; "\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Новый контакт"</b></font>", чтобы создать контакт \"с нуля\";"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Импорт/Экспорт."</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"У вас нет контактов."\n\n"Чтобы добавить контакты, нажмите "<font fgcolor="#ffffffff"><b>"Меню"</b></font>" и выберите:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Аккаунты"</b></font>", чтобы добавить или настроить аккаунт с контактами, которые можно будет синхронизировать с телефоном;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Новый контакт"</b></font>", чтобы создать контакт \"с нуля\";"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Импорт/Экспорт."</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"У вас нет контактов. (Если вы только что добавили аккаунт, синхронизация контактов может занять несколько минут.)"\n\n"Чтобы добавить контакты, нажмите "<font fgcolor="#ffffffff"><b>"Меню"</b></font>" и выберите:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Аккаунты"</b></font>", чтобы добавить или настроить аккаунт с контактами, которые можно будет синхронизировать с телефоном;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Варианты отображения"</b></font>", чтобы выбрать, какие контакты будут видны; "\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Новый контакт"</b></font>", чтобы создать контакт \"с нуля\";"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Импорт/Экспорт."</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"У вас нет избранных контактов."\n\n"Чтобы сделать контакт избранным,"\n\n" "<li>"нажмите вкладку "<b>"Контакты"</b>";"\n</li>" "\n<li>"нажмите контакт, который нужно сделать избранным;"\n</li>" "\n<li>"нажмите звездочку возле имени контакта."\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Выбрать группы для синхронизации"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Все контакты"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Все контакты"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Помеченные"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Телефоны"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Использовать тональный набор"</string>
@@ -164,8 +220,8 @@
<string name="ringtone_spinner" msgid="7317823545379736528">"Мелодия: <xliff:g id="RINGTONE">%1$s</xliff:g>"</string>
<string name="add_more_items" msgid="7754115197545456663">"Добавить сведения"</string>
<string name="actionCall" msgid="695145166039381504">"Вызов: <xliff:g id="TYPE">%s</xliff:g>"</string>
- <string name="actionEmail" msgid="3870371552333656807">"Электронная почта <xliff:g id="TYPE">%s</xliff:g>"</string>
- <string name="actionText" msgid="6399049224844880108">"Отправить текстовое сообщение <xliff:g id="TYPE">%s</xliff:g>"</string>
+ <string name="actionEmail" msgid="3870371552333656807">"Эл. почта: <xliff:g id="TYPE">%s</xliff:g>"</string>
+ <string name="actionText" msgid="6399049224844880108">"Послать SMS: <xliff:g id="TYPE">%s</xliff:g>"</string>
<string name="actionChat" msgid="31079429748650300">"Начать чат в <xliff:g id="TYPE">%s</xliff:g>"</string>
<string name="actionMap" msgid="1977955782051732775">"Адрес <xliff:g id="TYPE">%s</xliff:g> на карте"</string>
<string name="actionIncomingCall" msgid="6028930669817038600">"Входящие вызовы"</string>
@@ -176,84 +232,191 @@
<string name="returnCall" msgid="8171961914203617813">"Перезвонить"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g>:<xliff:g id="SECONDS">%s</xliff:g>"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Часто вызываемые"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Добление контакта"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Добавить контакт"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Добавить в контакты <xliff:g id="EMAIL">%s</xliff:g>?"</string>
- <!-- no translation found for description_image_button_one (1740638037139856139) -->
- <skip />
- <!-- no translation found for description_image_button_two (5882638439003731308) -->
- <skip />
- <!-- no translation found for description_image_button_three (8709731759376015180) -->
- <skip />
- <!-- no translation found for description_image_button_four (3530239685642246130) -->
- <skip />
- <!-- no translation found for description_image_button_five (1182465427501188413) -->
- <skip />
- <!-- no translation found for description_image_button_six (2093656269261415475) -->
- <skip />
- <!-- no translation found for description_image_button_seven (2450357020447676481) -->
- <skip />
- <!-- no translation found for description_image_button_eight (6969435115163287801) -->
- <skip />
- <!-- no translation found for description_image_button_nine (7857248695662558323) -->
- <skip />
- <!-- no translation found for description_image_button_star (3365919907520767866) -->
- <skip />
- <!-- no translation found for description_image_button_zero (4133108949401820710) -->
- <skip />
- <!-- no translation found for description_image_button_pound (3039765597595889230) -->
- <skip />
- <string name="no_sdcard_title" msgid="6455416795090113715">"Нет SD-карты"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"SD-карта не обнаружена"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Поиск VCard"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Все"</string>
+ <string name="description_image_button_one" msgid="1740638037139856139">"один"</string>
+ <string name="description_image_button_two" msgid="5882638439003731308">"два"</string>
+ <string name="description_image_button_three" msgid="8709731759376015180">"три"</string>
+ <string name="description_image_button_four" msgid="3530239685642246130">"четыре"</string>
+ <string name="description_image_button_five" msgid="1182465427501188413">"пять"</string>
+ <string name="description_image_button_six" msgid="2093656269261415475">"шесть"</string>
+ <string name="description_image_button_seven" msgid="2450357020447676481">"семь"</string>
+ <string name="description_image_button_eight" msgid="6969435115163287801">"восемь"</string>
+ <string name="description_image_button_nine" msgid="7857248695662558323">"девять"</string>
+ <string name="description_image_button_star" msgid="3365919907520767866">"пометить"</string>
+ <string name="description_image_button_zero" msgid="4133108949401820710">"нуль"</string>
+ <string name="description_image_button_pound" msgid="3039765597595889230">"решетка"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Нет SD-карты"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"SD-карта не обнаружена"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Поиск vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Откуда импортировать контакты?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIM-карта"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"SD-карта"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Импорт всех файлов VCard"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Импортировать один файл VCard"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Поиск данных VCard в файле VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Не удалось сканировать SD-карту"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Не удалось сканировать SD-карту"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Импортировать с SIM-карты"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Импортировать с SD-карты"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Экспортировать на SD-карту"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Импорт одного файла VCard"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Импорт нескольких файлов vCard"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Импорт всех файлов VCard"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Поиск данных vCard на SD-карте"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Не удалось сканировать SD-карту."</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Не удалось просканировать SD-карту (причина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"Ошибка ввода-вывода"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Не удается выполнить синтаксический анализ VCard"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"На SD-карте не найдены файлы VCard"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Нет подходящих записей VCard"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Выбор файла VCard"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Выберите файл VCard для импорта"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Чтение VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Чтение файлов VCard"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Импорт данных VCard"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Не удается считать данные VCard"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"Не удается прочитать данные VCard"\n"Причина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Не удалось обработать vCard по неизвестной причине."</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Не удалось обработать vCard. Файл правильного формата, но не поддерживается в текущей реализации."</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"На SD-карте не найдены файлы VCard"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Не найдено правильных записей vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Не удалось импортировать один или несколько файлов (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Неизвестная ошибка"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Выберите файл vCard"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Выберите файл vCard для импорта"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Чтение vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Чтение файлов VCard"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Импорт данных vCard"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Не удается считать данные vCard"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Не удается прочитать vCard."\n"Причина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"Контакт <xliff:g id="CURRENT_NUMBER">%s</xliff:g> из <xliff:g id="TOTAL_NUMBER">%s</xliff:g>"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"Файл <xliff:g id="CURRENT_NUMBER">%s</xliff:g> из <xliff:g id="TOTAL_NUMBER">%s</xliff:g>"</string>
- <!-- no translation found for export_contact_list (3165097742175874384) -->
- <skip />
- <!-- no translation found for confirm_export_title (1693047909433122854) -->
- <skip />
- <!-- no translation found for confirm_export_message (63482084706768079) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_title (1455264422455075858) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_message (1426451081541603512) -->
- <skip />
- <!-- no translation found for fail_reason_too_many_vcard (5416992255233341607) -->
- <skip />
- <!-- no translation found for fail_reason_too_long_filename (7105223965196949065) -->
- <skip />
- <!-- no translation found for fail_reason_cannot_open_destination_dir (1739293936432987758) -->
- <skip />
- <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
- <skip />
- <!-- no translation found for exporting_contact_list_message (5640326540405486055) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_initialize_exporter (4943708332700987376) -->
- <skip />
- <!-- no translation found for fail_reason_error_occurred_during_export (2151165129433831202) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_open_file (4013520943128739511) -->
- <skip />
- <!-- no translation found for exporting_contact_list_progress (560522409559101193) -->
- <skip />
- <!-- no translation found for search_settings_description (2675223022992445813) -->
- <skip />
+ <string name="export_all_contacts" msgid="2873892623335194071">"Все контакты"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Контакты, сохраненные локально"</string>
+ <string name="export_contact_list" msgid="3165097742175874384">"Экспорт контактов"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Подтверждение·экспорта"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Вы действительно хотите экспортировать контакты в файл <xliff:g id="VCARD_FILENAME">%s</xliff:g>?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Не удалось экспортировать данные контакта."</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Не удалось экспортировать данные контакта."\n"Причина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Нет контактов, которые можно экспортировать."</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"Слишком много файлов VCard на SD-карте."</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Название файла слишком длинное (<xliff:g id="FILENAME">%s</xliff:g>)."</string>
+ <string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Не удается открыть или создать целевой каталог \"<xliff:g id="DIR_NAME">%s</xliff:g>\""</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Экспорт данных контакта"</string>
+ <string name="exporting_contact_list_message" msgid="5640326540405486055">"Экспорт данных контакта в \"<xliff:g id="FILE_NAME">%s</xliff:g>\""</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Не удается запустить функцию экспорта: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Ошибка при экспорте: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Не удалось получить информацию из базы данных."</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Нет контактов, пригодных для экспорта. Можно выбрать неэкспортируемые данные."</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"Редактор vCard запущен некорректно"</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Не удается открыть \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_progress" msgid="560522409559101193">"Контакт <xliff:g id="CURRENT_NUMBER">%s</xliff:g> из <xliff:g id="TOTAL_NUMBER">%s</xliff:g>"</string>
+ <string name="search_settings_description" msgid="2675223022992445813">"Имена контактов"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Добавить двухсекундную паузу"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Добавить паузу"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Набор номера"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Вызов"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Отправить SMS с помощью"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Запомнить выбранное"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Отсутствует приложение для обработки этого действия"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Запомнить выбранное"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Неизвестно"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Аккаунты"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Импорт/Экспорт"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Импорт и экспорт контактов"</string>
+ <string name="menu_share" msgid="943789700636542260">"Отправить"</string>
+ <string name="share_via" msgid="563121028023030093">"Способ отправки"</string>
+ <string name="share_error" msgid="4374508848981697170">"Этот контакт нельзя отправить."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Имя"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Псевдоним"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Организация"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Веб-сайт"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Мероприятие"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"Д"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"М"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"Р"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"П"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"Др"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Этот контакт только для чтения"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Дополнительно"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Основное имя"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Создать контакт в аккаунте"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Удалить группу синхронизации"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Добавить группу синхронизации"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Другие группы..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Остальные контакты"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Все контакты"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Удаление группы \"<xliff:g id="GROUP">%s</xliff:g>\" из синхронизации приведет к удалению любых несгруппированных контактов из синхронизации."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Только телефон (несинхронизирован)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Показать имя"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Позвонить (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="call_home" msgid="1990519474420545392">"Позвонить (дом.)"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Позвонить (моб.)"</string>
+ <string name="call_work" msgid="5328785911463744028">"Позвонить (раб.)"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Позвонить (раб. факс)"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Позвонить (дом. факс)"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Позвонить (пейджер)"</string>
+ <string name="call_other" msgid="5605584621798108205">"Позвонить (другое)"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Вызов: номер обратного вызова"</string>
+ <string name="call_car" msgid="3280537320306436445">"Позвонить (автомоб.)"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Позвонить (раб., осн.)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Вызов: ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Вызов: основной"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Вызов: другой факс"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Позвонить (радиотел.)"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Вызов: телекс"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Вызов: телетайп"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Вызов: рабочий мобильный"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Вызов: рабочий пейджер"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Вызов: <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Позвонить (MMS)"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"SMS (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="sms_home" msgid="7524332261493162995">"SMS (дом.)"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"SMS (моб.)"</string>
+ <string name="sms_work" msgid="2269624156655267740">"SMS (дом.)"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"SMS (раб. факс)"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"SMS (дом. факс)"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"SMS (пейджер)"</string>
+ <string name="sms_other" msgid="5131921487474531617">"SMS (другое)"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Отправить SMS на номер обратного вызова"</string>
+ <string name="sms_car" msgid="7444227058437359641">"SMS (автомоб.)"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"SMS (раб., осн.)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Отправить SMS на номер ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Отправить SMS на основной номер"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Отправить текстовое сообщение на другой факс"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"SMS (радиотел.)"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Отправить SMS на телекс"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Отправить сообщение на телетайп"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Отправить SMS на рабочий мобильный"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Отправить сообщение на рабочий пейджер"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Отправить текстовое сообщение на номер <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"Эл. почта (дом.)"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Эл. почта (моб.)"</string>
+ <string name="email_work" msgid="2807430017302722689">"Эл. почта (раб.)"</string>
+ <string name="email_other" msgid="8093933498541795832">"Эл. почта (другое)"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Эл. почта (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="email" msgid="5668400997660065897">"Эл. почта"</string>
+ <string name="map_home" msgid="1243547733423343982">"Просмотреть домашний адрес"</string>
+ <string name="map_work" msgid="1360474076921878088">"Просмотреть рабочий адрес"</string>
+ <string name="map_other" msgid="5560707927535653892">"Просмотреть другой адрес"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Просмотр адреса: <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Чат через AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Чат через Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Чат через Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Чат через Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Чат через QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Чат через Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Чат через ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Чат через Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Чат"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Улица"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Почтовый ящик"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Окружение"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Город"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Регион"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Почтовый индекс"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Страна"</string>
+ <string name="name_given" msgid="1687286314106019813">"Имя"</string>
+ <string name="name_family" msgid="3416695586119999058">"Фамилия"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Префикс имени"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Отчество"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Суффикс имени"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Имя (фонетическая запись)"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Отчество (фонетическая запись)"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Фамилия (фонетическая запись)"</string>
+ <string name="split_label" msgid="8262112659919449087">"Разделить"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Сделать эти данные отдельным контактом."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Из аккаунта <xliff:g id="SOURCE">%1$s</xliff:g>: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"Контакт <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="from_account_format" msgid="687567483928582084">"из <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Использовать эту фотографию"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"Невозможно изменить контактную информацию <xliff:g id="SOURCE">%1$s</xliff:g> на этом устройстве."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Отсутствует дополнительная информация об этом контакте."</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 8c5dae6..17fe14e 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -16,18 +16,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Kontakter"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Samtal"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefon"</string>
<string name="shortcutContact" msgid="749243779392912958">"Kontakt"</string>
- <!-- no translation found for shortcutDialContact (7165340343023469996) -->
- <skip />
- <!-- no translation found for shortcutMessageContact (3025782962770298900) -->
- <skip />
- <!-- no translation found for shortcutActivityTitle (6642877210643565436) -->
- <skip />
- <!-- no translation found for callShortcutActivityTitle (6065749861423648991) -->
- <skip />
- <!-- no translation found for messageShortcutActivityTitle (3084542316620335911) -->
- <skip />
+ <string name="shortcutDialContact" msgid="746622101599186779">"Direktval"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Direktmeddelande"</string>
+ <string name="shortcutActivityTitle" msgid="6642877210643565436">"Välj genväg till kontakten"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"Välj ett nummer som du vill ringa"</string>
+ <string name="messageShortcutActivityTitle" msgid="3084542316620335911">"Välj ett nummer för meddelandet"</string>
<string name="starredList" msgid="4817256136413959463">"Stjärnmärkta"</string>
<string name="frequentList" msgid="7154768136473953056">"Ofta"</string>
<string name="strequentList" msgid="5640192862059373511">"Favoriter"</string>
@@ -45,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Visa streckkod"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Redigera kontakt"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Ta bort kontakt"</string>
- <string name="menu_call" msgid="7359207953236681606">"Ring"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"Skicka SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Ring upp kontakt"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Skicka SMS till kontakt"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"Skicka e-post"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Visa adress på karta"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Använd som standardnummer"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Använd som standardadress"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Dela upp"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Avdela kontakt"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Kontakterna har delats upp"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Dela upp kontakt"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Vill du dela upp den här kontakten i flera kontakter, en för varje uppsättning kontaktinformation som kombinerats i den?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Gå med"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Visa källor"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Dölj källor"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Anslut kontakt"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Kombinera kontakter"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"Välj en kontakt som du vill slå ihop med <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Visa alla kontakter"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Föreslagna kontakter"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Alla kontakter"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Deltagande kontakter"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Alternativ"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Alternativ"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Ta bort"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Det går inte att ta bort kontakter från skrivskyddade konton, men du kan dölja dem i kontaktlistan."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Den här kontakten har information från flera konton. Information från skrivskyddade konton döljs i kontaktlistan, men tas inte bort."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Om du tar bort den här kontakten tar du bort information från flera konton."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Kontakten kommer att tas bort."</string>
<string name="menu_done" msgid="796017761764190697">"Färdig"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Återgå"</string>
@@ -60,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonetiskt"</string>
<string name="label_notes" msgid="8337354953278341042">"Anteckningar"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Ringsignal"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Grupper"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Redigera grupper"</string>
<string name="ghostData_name" msgid="6490954238641157585">"För- och efternamn"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Fonetiskt namn"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Företag"</string>
@@ -69,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Telefonnummer"</string>
<string name="ghostData_email" msgid="6184537075551565919">"E-postadress"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Postadress"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Visa grupp"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Kontakten finns inte."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Skapa ny kontakt"</string>
<string name="selectLabel" msgid="4255424123394910733">"Välj etikett"</string>
@@ -85,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Det finns inga bilder på telefonen."</string>
<string name="attachToContact" msgid="8820530304406066714">"Kontaktikon"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Anpassat etikettsnamn"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Visa grupper"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Visningsalternativ"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Visa alternativ"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Redigera synkgrupper"</string>
<string name="importFromSim" msgid="8383900146531125319">"Importera kontakter"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Skicka samtal direkt till röstbrevlåda"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Samtal skickas direkt till röstbrevlådan."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Standardinställning"</string>
<string name="addPicture" msgid="1594679312161537678">"Lägg till ikon"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Ändra ikon"</string>
<string name="removePicture" msgid="3041230993155966350">"Ta bort ikon"</string>
<string name="noContacts" msgid="8579310973261953559">"Inga kontakter."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Inga matchande kontakter hittades."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Inga kontakter med telefonnummer."</string>
<string name="noFavorites" msgid="812766386743315815">"Inga favoriter."</string>
<string name="select_group_title" msgid="7955698611959835612">"Grupper"</string>
<string name="groupEmpty" msgid="6661950109828194595">"Din grupp, <xliff:g id="GROUPNAME">%s</xliff:g>, är tom."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Alla kontakter"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Bara kontakter med telefoner"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Visa bara kontakter med telefonnummer"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Välj kontakter att visa"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> kontakter"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> kontakter, <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> med telefon"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Synka alla kontakter"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Mina kontakter"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Mina kontakter"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Kontakter med telefonnummer"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Stjärnmärkta i Android"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Sparar kontakt..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Sparar visningsalternativ ..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Kontakt skapad."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Kontakt sparad."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Fel: det går inte att spara kontakter."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Ring upp"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Telefonnummer"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"Skicka SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"Skicka SMS"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"Skicka e-post"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"E-postadresser"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Skicka snabbmeddelande"</string>
@@ -115,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Visa adress på karta"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Postadress"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Organisationer"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Grupper"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Övrig information"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Övriga alternativ"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Mer"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Visar en kontakt med telefonnummer"</item>
+ <item quantity="other" msgid="6133262880804110289">"Visar <xliff:g id="COUNT">%d</xliff:g> kontakter med telefonnummer"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Inga synliga kontakter med telefonnummer"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"Visar en kontakt"</item>
+ <item quantity="other" msgid="2865867557378939630">"Visar <xliff:g id="COUNT">%d</xliff:g> kontakter"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Det finns inga synliga kontakter"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"En kontakt hittades"</item>
+ <item quantity="other" msgid="7752927996850263152">"<xliff:g id="COUNT">%d</xliff:g> kontakter hittades"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Kontakten hittades inte"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Socialt"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kontakter"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriter"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Samtal"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Samtalshistorik"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Alla kontakter"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Stjärnmärkta kontakter"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Kontakter med telefonnummer"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"Skicka SMS"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Skicka SMS"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"Ring <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Redigera nummer före samtal"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Lägg till i Kontakter"</string>
@@ -133,19 +185,23 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Rensa samtalshistorik"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Samtalshistoriken är tom."</string>
<string name="imei" msgid="3045126336951684285">"IMEI-kod"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Röstbrevlåda"</string>
<string name="unknown" msgid="740067747858270469">"Okänd"</string>
<string name="private_num" msgid="6374339738119166953">"Privat nummer"</string>
<string name="payphone" msgid="4864313342828942922">"Telefonautomat"</string>
<string name="dialerKeyboardHintText" msgid="5401660096579787344">"Använd tangentbordet när du ringer"</string>
- <string name="dialerDialpadHintText" msgid="5824490365898349041">"Ring om du vill lägga till ett samtal"</string>
+ <string name="dialerDialpadHintText" msgid="5824490365898349041">"Ring/lägga till"</string>
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"Läser in från SIM-kort…"</string>
<string name="simContacts_title" msgid="27341688347689769">"Kontakter från SIM-kort"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Synka dina Google-kontakter!"</font>" "\n"När du har synkat med telefonen kan du använda dina kontakter var du än är."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Du har inga kontakter."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och väljer:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en helt ny kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera kontakter"</b></font>" om du vill lägga till kontakter från SIM-kortet"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Du har inga kontakter."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och väljer:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Redigera synkgrupper"</b></font>" om du vill lägga till från ett nytt eller befintligt Google-konto"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill lägga till en helt ny kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera kontakter"</b></font>" om du vill lägga till kontakter från SIM-kortet"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Det finns inga kontakter att visa."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som kan synkroniseras till telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Det finns inga kontakter att visa (om du nyss har lagt till ett konto kan det ta några minuter att synkronisera kontakter)."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som kan synkroniseras till telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativ"</b></font>" om du vill ändra vilka kontakter som är synliga"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Det finns inga kontakter att visa."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som kan synkroniseras till telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Det finns inga kontakter att visa (om du nyss har lagt till ett konto kan det ta några minuter att synkronisera kontakter)."\n\n"Om du vill lägga till kontakter trycker du på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" och sedan på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Konton"</b></font>" om du vill lägga till eller konfigurera ett konto med kontakter som kan synkroniseras till telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativ"</b></font>" om du vill ändra vilka kontakter som är synliga"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" om du vill skapa en ny kontakt från grunden"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importera/exportera"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Du har inte några favoriter."\n\n"Så här lägger du till kontakter i favoritlistan:"\n\n" "<li>"Tryck på fliken "<b>"Kontakter"</b>\n</li>" "\n<li>"Tryck på den kontakt du vill lägga till i favoriterna"\n</li>" "\n<li>"Tryck på stjärnan bredvid kontaktens namn"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Välj grupper att synka"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Alla kontakter"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Alla kontakter"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Stjärnmärkt"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Telefoner"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Använda tonvalstelefon"</string>
@@ -176,84 +232,191 @@
<string name="returnCall" msgid="8171961914203617813">"Ring upp"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> minuter <xliff:g id="SECONDS">%s</xliff:g> sekunder"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Ringer ofta"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Lägg till kontakt"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Lägg till kontakt"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Vill du lägga till <xliff:g id="EMAIL">%s</xliff:g> i Kontakter?"</string>
- <!-- no translation found for description_image_button_one (1740638037139856139) -->
- <skip />
- <!-- no translation found for description_image_button_two (5882638439003731308) -->
- <skip />
- <!-- no translation found for description_image_button_three (8709731759376015180) -->
- <skip />
- <!-- no translation found for description_image_button_four (3530239685642246130) -->
- <skip />
- <!-- no translation found for description_image_button_five (1182465427501188413) -->
- <skip />
- <!-- no translation found for description_image_button_six (2093656269261415475) -->
- <skip />
- <!-- no translation found for description_image_button_seven (2450357020447676481) -->
- <skip />
- <!-- no translation found for description_image_button_eight (6969435115163287801) -->
- <skip />
- <!-- no translation found for description_image_button_nine (7857248695662558323) -->
- <skip />
- <!-- no translation found for description_image_button_star (3365919907520767866) -->
- <skip />
- <!-- no translation found for description_image_button_zero (4133108949401820710) -->
- <skip />
- <!-- no translation found for description_image_button_pound (3039765597595889230) -->
- <skip />
- <string name="no_sdcard_title" msgid="6455416795090113715">"Inget SD-kort"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Inget SD-kort hittades"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"Söker efter VCard"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Alla"</string>
+ <string name="description_image_button_one" msgid="1740638037139856139">"ett"</string>
+ <string name="description_image_button_two" msgid="5882638439003731308">"två"</string>
+ <string name="description_image_button_three" msgid="8709731759376015180">"tre"</string>
+ <string name="description_image_button_four" msgid="3530239685642246130">"fyra"</string>
+ <string name="description_image_button_five" msgid="1182465427501188413">"fem"</string>
+ <string name="description_image_button_six" msgid="2093656269261415475">"sex"</string>
+ <string name="description_image_button_seven" msgid="2450357020447676481">"sju"</string>
+ <string name="description_image_button_eight" msgid="6969435115163287801">"åtta"</string>
+ <string name="description_image_button_nine" msgid="7857248695662558323">"nio"</string>
+ <string name="description_image_button_star" msgid="3365919907520767866">"Stjärna"</string>
+ <string name="description_image_button_zero" msgid="4133108949401820710">"noll"</string>
+ <string name="description_image_button_pound" msgid="3039765597595889230">"pund"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"Inget SD-kort"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Inget SD-kort hittades"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"Söker efter vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Varifrån vill du importera dina kontakter?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIM-kort"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"SD-kort"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Importera alla VCard-filer"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Importera en VCard-fil"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"Söker efter VCard-data på VCard"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"Det gick inte att läsa SD-kort"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"Det gick inte att skanna SD-kort"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"Importera från SIM-kort"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"Importera från SD-kort"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"Exportera till SD-kort"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Importera en vCard-fil"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Importera flera vCard-filer"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Importera alla vCard-filer"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"Söker efter vCard-data på SD-kort"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"Det gick inte att läsa SD-kort"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"Det gick inte att skanna SD-kortet (orsak: <xliff:g id="FAIL_REASON">%s</xliff:g>)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O-fel"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"Det gick inte att analysera VCard"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"Ingen VCard-fil hittades på SD-kortet"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Det finns ingen VCard-post i den valda filen"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"Välj VCard-fil"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Välj en VCard-fil att importera"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"Läser VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"Läser VCard-filer"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"Importera VCard-data"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"Det gick inte att läsa VCard-data"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"Det gick inte att läsa VCard-data"\n"Anledning: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Det gick inte att analysera vCard av okänd anledning"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Det gick inte att analysera vCard trots att formatet verkar vara giltigt. Den aktuella implementeringen stöder inte det."</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"Ingen vCard-fil hittades på SD-kortet"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Det finns ingen vCard-post i den valda filen"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"En eller flera filer kunde inte importeras: (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Okänt fel"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"Välj vCard-fil"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Välj en vCard-fil att importera"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"Läser vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"Läser vCard-filer"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"Importera vCard-data"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"Det gick inte att läsa vCard-data"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"Det gick inte att läsa vCard."\n"Orsak: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> av <xliff:g id="TOTAL_NUMBER">%s</xliff:g> kontakter"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> av <xliff:g id="TOTAL_NUMBER">%s</xliff:g> filer"</string>
- <!-- no translation found for export_contact_list (3165097742175874384) -->
- <skip />
- <!-- no translation found for confirm_export_title (1693047909433122854) -->
- <skip />
- <!-- no translation found for confirm_export_message (63482084706768079) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_title (1455264422455075858) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_message (1426451081541603512) -->
- <skip />
- <!-- no translation found for fail_reason_too_many_vcard (5416992255233341607) -->
- <skip />
- <!-- no translation found for fail_reason_too_long_filename (7105223965196949065) -->
- <skip />
- <!-- no translation found for fail_reason_cannot_open_destination_dir (1739293936432987758) -->
- <skip />
- <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
- <skip />
- <!-- no translation found for exporting_contact_list_message (5640326540405486055) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_initialize_exporter (4943708332700987376) -->
- <skip />
- <!-- no translation found for fail_reason_error_occurred_during_export (2151165129433831202) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_open_file (4013520943128739511) -->
- <skip />
- <!-- no translation found for exporting_contact_list_progress (560522409559101193) -->
- <skip />
- <!-- no translation found for search_settings_description (2675223022992445813) -->
- <skip />
+ <string name="export_all_contacts" msgid="2873892623335194071">"Alla kontakter"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Lokalt sparade kontakter"</string>
+ <string name="export_contact_list" msgid="3165097742175874384">"Exportera kontakter"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Bekräfta export"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Vill du exportera kontaktlistan till \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\"?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Det gick inte att exportera kontaktdata"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Det gick inte att exportera kontaktdata."\n"Orsak: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Det finns ingen kontakt som kan exporteras"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"För många vCard-filer på SD-kortet"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Det obligatoriska filnamnet är för långt (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"Det går inte att öppna målkatalogen <xliff:g id="DIR_NAME">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exporterar kontaktuppgifter"</string>
+ <string name="exporting_contact_list_message" msgid="5640326540405486055">"Exporterar kontaktuppgifter till: <xliff:g id="FILE_NAME">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Det gick inte att starta exportverktyget: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Ett fel uppstod under export: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Det gick inte att hämta databasinformation"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Det finns ingen kontakt som kan exporteras. Du kan välja data som inte kan exporteras"</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"vCard-kompositören är inte korrekt initierad"</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"Det gick inte att öppna <xliff:g id="FILE_NAME">%s</xliff:g>: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_progress" msgid="560522409559101193">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> av <xliff:g id="TOTAL_NUMBER">%s</xliff:g> kontakter"</string>
+ <string name="search_settings_description" msgid="2675223022992445813">"Dina kontakters namn"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"Lägg till en paus på 2 sek."</string>
+ <string name="add_wait" msgid="3360818652790319634">"Lägg till väntetid"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Ring"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Ring upp med"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Skicka SMS med"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Kom ihåg det här valet"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Inget program som kan hantera åtgärden hittades"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Kom ihåg det här valet"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Okänd"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Konton"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"Importera/exportera"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Importera/exportera kontakter"</string>
+ <string name="menu_share" msgid="943789700636542260">"Dela"</string>
+ <string name="share_via" msgid="563121028023030093">"Dela kontakt via"</string>
+ <string name="share_error" msgid="4374508848981697170">"Den här kontakten kan inte delas."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Namn"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Smeknamn"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Webbplats"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Händelse"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"H"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"A"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"P"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"A"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Kontakten är skrivskyddad"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Mer"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Primärt namn"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Skapa kontakt under konto"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Ta bort synkgrupp"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Lägg till synkgrupp"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Fler grupper …"</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Alla andra kontakter"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Alla kontakter"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"Om du tar bort \"<xliff:g id="GROUP">%s</xliff:g>\" från synkroniseringen tas även alla kontakter som inte tillhör grupper bort från synkroniseringen."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Bara telefon (osynkad)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Visningsnamn"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Ring <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Ring hem"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Ring mobilen"</string>
+ <string name="call_work" msgid="5328785911463744028">"Ring – arbete"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Ring – arbetsfax"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Ring upp hemfax"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Ring personsökare"</string>
+ <string name="call_other" msgid="5605584621798108205">"Ring – annan"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Ring upp återuppringningsnummer"</string>
+ <string name="call_car" msgid="3280537320306436445">"Ring bilen"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Ring företagets växel"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Ring upp ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Ring upp primärt nummer"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Ring upp annan fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Ring radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Ring upp telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Ring upp TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Ring upp jobbmobil"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Ring upp jobbpersonsökare"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Ring <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Samtal – MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Skicka SMS till <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"SMS – hem"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"SMS – mobil"</string>
+ <string name="sms_work" msgid="2269624156655267740">"SMS – arbete"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"SMS – arbetsfax"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"SMS – hemfax"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"SMS – personsökare"</string>
+ <string name="sms_other" msgid="5131921487474531617">"SMS – annan"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Skicka SMS till återuppringningsnummer"</string>
+ <string name="sms_car" msgid="7444227058437359641">"SMS – bil"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"SMS – jobbväxel"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Skicka SMS till ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Skicka SMS till primärt nummer"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"Skicka SMS till annan fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"SMS – radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Skicka SMS till telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Skicka SMS till TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Skicka SMS till jobbmobil"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Skicka SMS till jobbpersonsökare"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Skicka SMS till <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Skicka MMS"</string>
+ <string name="email_home" msgid="8573740658148184279">"E-postadress – hem"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Skicka e-post till mobil"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-postadress – arbete"</string>
+ <string name="email_other" msgid="8093933498541795832">"Skicka e-post till annan"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Skicka e-post till <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-post"</string>
+ <string name="map_home" msgid="1243547733423343982">"Visa hemadress"</string>
+ <string name="map_work" msgid="1360474076921878088">"Visa jobbadress"</string>
+ <string name="map_other" msgid="5560707927535653892">"Visa annan adress"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Visa adress, <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chatta med AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chatta med Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chatta med Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chatta med Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chatta med QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chatta med Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chatta med ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chatta med Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chatt"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Gata"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Postbox"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Område"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Stad"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Delstat"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postnummer"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Land"</string>
+ <string name="name_given" msgid="1687286314106019813">"Förnamn"</string>
+ <string name="name_family" msgid="3416695586119999058">"Efternamn"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Namnprefix"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Mellannamn"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Namnsuffix"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Fonetiskt förnamn"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetiskt mellannamn"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Fonetiskt efternamn"</string>
+ <string name="split_label" msgid="8262112659919449087">"Dela"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Gör dessa data till en egen kontakt."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"Från <xliff:g id="SOURCE">%1$s</xliff:g>-konto: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g>-kontakt"</string>
+ <string name="from_account_format" msgid="687567483928582084">"från <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Använd det här fotot"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"Kontaktinformation för <xliff:g id="SOURCE">%1$s</xliff:g> kan inte redigeras i den här enheten."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Det finns ingen mer information för kontakten"</string>
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 7128112..d55306b 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -16,18 +16,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"Kişiler"</string>
- <string name="launcherDialer" msgid="140610573639849799">"Çevirici"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"Telefon"</string>
<string name="shortcutContact" msgid="749243779392912958">"Kişi"</string>
- <!-- no translation found for shortcutDialContact (7165340343023469996) -->
- <skip />
- <!-- no translation found for shortcutMessageContact (3025782962770298900) -->
- <skip />
- <!-- no translation found for shortcutActivityTitle (6642877210643565436) -->
- <skip />
- <!-- no translation found for callShortcutActivityTitle (6065749861423648991) -->
- <skip />
- <!-- no translation found for messageShortcutActivityTitle (3084542316620335911) -->
- <skip />
+ <string name="shortcutDialContact" msgid="746622101599186779">"Doğrudan çevirme"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"Doğrudan ileti"</string>
+ <string name="shortcutActivityTitle" msgid="6642877210643565436">"Bir kişi kısayolu seçin"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"Aranacak numarayı seçin"</string>
+ <string name="messageShortcutActivityTitle" msgid="3084542316620335911">"İleti gönderilecek bir numara seçin"</string>
<string name="starredList" msgid="4817256136413959463">"Yıldızlı"</string>
<string name="frequentList" msgid="7154768136473953056">"Sık sık"</string>
<string name="strequentList" msgid="5640192862059373511">"Sık Kullanılanlar"</string>
@@ -45,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"Barkodu göster"</string>
<string name="menu_editContact" msgid="3452858480713561396">"Kişiyi düzenle"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"Kişiyi sil"</string>
- <string name="menu_call" msgid="7359207953236681606">"Çağrı"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"SMS/MMS gönder"</string>
+ <string name="menu_call" msgid="3992595586042260618">"Çağrı: (kişi)"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"Şu kişiye SMS veya MMS gönder:"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"E-posta gönder"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"Adresi haritada göster"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"Varsayılan numara yap"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"Varsayılan e-posta yap"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"Ayır"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"Kişiyi ayır"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"Kişi ayrıldı"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"Kişiyi Ayır"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"Bu tek kişiyi birden fazla kişiye ayırmak istediğinizden emin misiniz? Bu kişiye eklenen kişi bilgileri setinin her biri için bir kişi oluşturulsun mu?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"Katıl"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"Kaynakları göster"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"Kaynakları gizle"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"Kişilere katıl"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"Kişiler\'e katıl"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"<xliff:g id="NAME">%s</xliff:g> ile katılmak istediğiniz kişiyi seçin."</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"Tüm kişileri göster"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"Önerilen kişiler"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"Tüm kişiler"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"Katılan kişiler"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"Seçenekler"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"Seçenekler"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"Sil"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"Kişileri salt okunur hesaplardan silemezsiniz ancak bu kişileri kişiler listenizde gizleyebilirsiniz."</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"Bu kişi birden fazla hesaptan bilgiler içeriyor. Salt okunur hesaplardaki bilgiler silinmez, kişiler listelerinizde gizlenir."</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"Bu kişiyi silmek, birden fazla hesaba ait bilgileri de siler."</string>
<string name="deleteConfirmation" msgid="811706994761610640">"Bu kişi silinecek."</string>
<string name="menu_done" msgid="796017761764190697">"Bitti"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"Geri Döndür"</string>
@@ -60,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"Fonetik"</string>
<string name="label_notes" msgid="8337354953278341042">"Notlar"</string>
<string name="label_ringtone" msgid="8833166825330686244">"Zil sesi"</string>
+ <string name="label_groups" msgid="7304551384542859026">"Gruplar"</string>
+ <string name="group_list" msgid="8583361685440161307">", <xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"Grupları düzenle"</string>
<string name="ghostData_name" msgid="6490954238641157585">"Adı ve Soyadı"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"Fonetik adı"</string>
<string name="ghostData_company" msgid="5414421120553765775">"Şirket"</string>
@@ -69,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"Telefon numarası"</string>
<string name="ghostData_email" msgid="6184537075551565919">"E-posta adresi"</string>
<string name="ghostData_postal" msgid="652611650594951897">"Posta adresi"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"Grubu görüntüle"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"Kişi mevcut değil."</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"Yeni kişi oluştur"</string>
<string name="selectLabel" msgid="4255424123394910733">"Etiketi seç"</string>
@@ -85,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"Telefonda hiçbir resim yok."</string>
<string name="attachToContact" msgid="8820530304406066714">"Kişi simgesi"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Özel etiket adı"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"Grubu görüntüle"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"Seçenekleri görüntüle"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"Seçenekleri görüntüle"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"Senk. grupları düzenle"</string>
<string name="importFromSim" msgid="8383900146531125319">"Kişileri içe aktar"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Çağrıları doğrudan sesli mesaja gönder"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"Aramalar doğrudan sesli mesaja gönderildi."</string>
<string name="default_ringtone" msgid="9099988849649827972">"Varsayılan"</string>
<string name="addPicture" msgid="1594679312161537678">"Simge ekle"</string>
+ <string name="changePicture" msgid="2943329047610967714">"Simgeyi değiştir"</string>
<string name="removePicture" msgid="3041230993155966350">"Simgeyi kaldır"</string>
<string name="noContacts" msgid="8579310973261953559">"Hiçbir kişi yok."</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"Eşleşen kişi bulunamadı."</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"Telefon numarası olan hiçbir kişi yok."</string>
<string name="noFavorites" msgid="812766386743315815">"Sık kullanılan yok."</string>
<string name="select_group_title" msgid="7955698611959835612">"Gruplar"</string>
<string name="groupEmpty" msgid="6661950109828194595">"\"<xliff:g id="GROUPNAME">%s</xliff:g>\" grubunuz boş."</string>
<string name="showAllGroups" msgid="5164410117611094297">"Tüm kişiler"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"Yalnızca telefonu olan kişiler"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"Yalnızca telefon numarası olan kişileri görüntüle"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"Görüntülenecek kişileri seçin"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> kişi"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> kişi, telefonu olan <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> kişi"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"Tüm kişileri senkronize et"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"Kişilerim"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"Kişilerim"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"Telefon numarası olan kişiler"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Android\'de yıldızlı"</string>
+ <string name="savingContact" msgid="4075751076741924939">"Kişi kaydediliyor..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Görüntüleme seçenekleri kaydediliyor..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"Kişi oluşturuldu."</string>
<string name="contactSavedToast" msgid="7152589189385441091">"Kişi kaydedildi."</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"Hata, kişi değişiklikleri kaydedilemiyor."</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"Numarayı çevir"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"Telefon numaraları"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"SMS/MMS gönder"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"SMS gönder"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"E-posta gönder"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"E-posta adresleri"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"Anlık ileti gönder"</string>
@@ -115,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"Adresi haritada göster"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"Posta adresleri"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"Kuruluşlar"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"Gruplar"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"Diğer bilgiler"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"Diğer seçenekler"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"Diğer"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"Telefon numarası olan 1 kişi görüntüleniyor"</item>
+ <item quantity="other" msgid="6133262880804110289">"Telefon numarası olan <xliff:g id="COUNT">%d</xliff:g> kişi görüntüleniyor"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"Telefon numarası olan görülebilir kişi yok"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"1 kişi görüntüleniyor"</item>
+ <item quantity="other" msgid="2865867557378939630">"<xliff:g id="COUNT">%d</xliff:g> kişi görüntüleniyor"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"Görülebilir kişi yok"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"1 kişi bulundu"</item>
+ <item quantity="other" msgid="7752927996850263152">"<xliff:g id="COUNT">%d</xliff:g> kişi bulundu"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"Kişi bulunamadı"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"Sosyal"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"Kişiler"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"Sık Kullanılanlar"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"Çevirici"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"Telefon"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"Çağrı kaydı"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"Tüm kişiler"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"Yıldızlı kişiler"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"Telefon numarası olan kişiler"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"SMS mesajı gönder"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"Kısa mesaj gönder"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"<xliff:g id="NAME">%s</xliff:g> adlı kişiyi ara"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"Aramadan önce numarayı düzenle"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"Kişilere ekle"</string>
@@ -133,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"Çağrı kaydını temizle"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"Çağrı kaydı boş."</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"Sesli Mesaj"</string>
<string name="unknown" msgid="740067747858270469">"Bilinmiyor"</string>
<string name="private_num" msgid="6374339738119166953">"Özel numara"</string>
@@ -142,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"SIM karttan yükleniyor..."</string>
<string name="simContacts_title" msgid="27341688347689769">"SIM kart kişileri"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"Google kişilerinizi senkronize edin!"</font>" "\n"Telefonunuzu senkronize ettikten sonra, kişilerinize gittiğiniz her yerden ulaşabilirsiniz."</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"Hiçbir kişiye sahip değilsiniz."\n\n"Kişi eklemek için "<font fgcolor="#ffffffff"><b>"Menü"</b></font>"\'ye basın ve şunu seçin:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Yeni kişi"</b></font>" (yeni bir kişi oluşturmak için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Kişileri içe aktar"</b></font>" (kişileri SIM kartınızdan almak için)"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"Hiçbir kişiniz yok."\n\n"Kişi eklemek için "<font fgcolor="#ffffffff"><b>"Menü"</b></font>"\'ye basın ve şunu seçin:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Senk. grupları düzenle"</b></font>" (yeni veya mevcut bir Google hesabından eklemek için )"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Yeni kişi"</b></font>" (yeni bir kişi oluşturmak için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Kişileri içe aktar"</b></font>" (kişileri SIM kartınızdan eklemek için)"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"Görüntülenecek hiçbir kişiniz yok."\n\n"Kişi eklemek için, "<font fgcolor="#ffffffff"><b>"Menü"</b></font>"\'ye basın ve şunlara dokunun:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Hesaplar"</b></font>" (telefon ile senkronize edebileceğiniz kişilere sahip olan bir hesap eklemek veya yapılandırmak için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Yeni kişi"</b></font>" (en baştan yeni bir kişi eklemek için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"İçe/Dışa Aktar"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"Görüntülenecek hiçbir kişiniz yok. (Kısa süre önce bir hesap eklediyseniz, kişileri senkronize etmek birkaç dakika sürebilir.)"\n\n"Kişi eklemek için, "<font fgcolor="#ffffffff"><b>"Menü"</b></font>"\'ye basın ve şunlara dokunun:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Hesaplar"</b></font>" (telefon ile senkronize edebileceğiniz kişilere sahip olan bir hesap eklemek veya yapılandırmak için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Seçenekleri görüntüle"</b></font>" (görülebilir kişileri değiştirmek için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Yeni kişi"</b></font>" (en baştan yeni bir kişi oluşturmak için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"İçe/Dışa Aktar"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"Görüntülenecek hiçbir kişiniz yok."\n\n"Kişi eklemek için, "<font fgcolor="#ffffffff"><b>"Menü"</b></font>"\'ye basın ve şunlara dokunun:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Hesaplar"</b></font>" (telefon ile senkronize edebileceğiniz kişilere sahip olan bir hesap eklemek veya yapılandırmak için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Yeni kişi"</b></font>" (en baştan yeni bir kişi eklemek için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"İçe/Dışa Aktar"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"Görüntülenecek hiçbir kişiniz yok. (Kısa süre önce bir hesap eklediyseniz, kişileri senkronize etmek birkaç dakika sürebilir.)"\n\n"Kişi eklemek için, "<font fgcolor="#ffffffff"><b>"Menü"</b></font>"\'ye basın ve şunlara dokunun:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Hesaplar"</b></font>" (telefon ile senkronize edebileceğiniz kişilere sahip olan bir hesap eklemek veya yapılandırmak için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Seçenekleri görüntüle"</b></font>" (görülebilir kişileri değiştirmek için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Yeni kişi"</b></font>" (en baştan yeni bir kişi oluşturmak için)"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"İçe/Dışa Aktar"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"Favoriniz bulunmuyor."\n\n"Favoriler listenize kişi eklemek için:"\n\n" "<li><b>"Kişiler"</b>" sekmesine dokunun"\n</li>" "\n<li>"Favorilerinize eklemek istediğiniz kişiye dokunun"\n</li>" "\n<li>"Kişi adının yanındaki yıldız simgesine dokunun"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"Senkronize edilecek grupları seç"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"Tüm Kişiler"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"Tüm kişiler"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"Yıldızlı"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"Telefonlar"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"Telefon tuş takımını kullan"</string>
@@ -176,84 +232,191 @@
<string name="returnCall" msgid="8171961914203617813">"Geri ara"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> dak <xliff:g id="SECONDS">%s</xliff:g> sn"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"Sık aranan"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"Kişi Ekle"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"Kişi ekle"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"\"<xliff:g id="EMAIL">%s</xliff:g>\" adresi kişilere eklensin mi?"</string>
- <!-- no translation found for description_image_button_one (1740638037139856139) -->
- <skip />
- <!-- no translation found for description_image_button_two (5882638439003731308) -->
- <skip />
- <!-- no translation found for description_image_button_three (8709731759376015180) -->
- <skip />
- <!-- no translation found for description_image_button_four (3530239685642246130) -->
- <skip />
- <!-- no translation found for description_image_button_five (1182465427501188413) -->
- <skip />
- <!-- no translation found for description_image_button_six (2093656269261415475) -->
- <skip />
- <!-- no translation found for description_image_button_seven (2450357020447676481) -->
- <skip />
- <!-- no translation found for description_image_button_eight (6969435115163287801) -->
- <skip />
- <!-- no translation found for description_image_button_nine (7857248695662558323) -->
- <skip />
- <!-- no translation found for description_image_button_star (3365919907520767866) -->
- <skip />
- <!-- no translation found for description_image_button_zero (4133108949401820710) -->
- <skip />
- <!-- no translation found for description_image_button_pound (3039765597595889230) -->
- <skip />
- <string name="no_sdcard_title" msgid="6455416795090113715">"SD Kart yok"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"Hiçbir SD Kart tespit edilmedi"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"VCard aranıyor"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"Tümü"</string>
+ <string name="description_image_button_one" msgid="1740638037139856139">"bir"</string>
+ <string name="description_image_button_two" msgid="5882638439003731308">"iki"</string>
+ <string name="description_image_button_three" msgid="8709731759376015180">"üç"</string>
+ <string name="description_image_button_four" msgid="3530239685642246130">"dört"</string>
+ <string name="description_image_button_five" msgid="1182465427501188413">"beş"</string>
+ <string name="description_image_button_six" msgid="2093656269261415475">"altı"</string>
+ <string name="description_image_button_seven" msgid="2450357020447676481">"yedi"</string>
+ <string name="description_image_button_eight" msgid="6969435115163287801">"sekiz"</string>
+ <string name="description_image_button_nine" msgid="7857248695662558323">"dokuz"</string>
+ <string name="description_image_button_star" msgid="3365919907520767866">"yıldız"</string>
+ <string name="description_image_button_zero" msgid="4133108949401820710">"sıfır"</string>
+ <string name="description_image_button_pound" msgid="3039765597595889230">"pound"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"SD kart yok"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"Hiçbir SD kart tespit edilmedi"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"vCard aranıyor"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"Kişilerin nereden içe aktarılmasını istiyorsunuz?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIM Kart"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"SD Kart"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"Tüm VCard dosyalarını içe aktar"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"Bir VCard dosyası içe aktar"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"VCard üzerinde VCard verileri aranıyor"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"SD kartın taranması başarısız oldu"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"SD kartın taranması başarısız oldu"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM karttan içe aktar"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"SD karttan içe aktar"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"SD kart için dışa aktar"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"Bir vCard dosyasını içe aktar"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"Birden fazla vCard dosyasını içe aktar"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"Tüm vCard dosyalarını içe aktar"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"SD kartta vCard verileri aranıyor"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"SD kart taranamadı"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"SD kart taraması başarısız oldu (Neden: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"G/Ç Hatası"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"VCard ayrıştırma başarısız"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"SD Kartta hiçbir VCard dosyası bulunamadı"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"Seçiminiz için geçerli VCard kaydı bulunamadı"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"VCard dosyasını seç"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"Lütfen içe aktarılacak bir VCard dosyası seçin"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"VCard okunuyor"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"VCard dosyaları okunuyor"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"VCard verileri içe aktarılıyor"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"VCard verilerinin okunması başarısız oldu"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"VCard verileri okunamadı"\n"Sorunun nedeni: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Beklenmedik bir nedenden dolayı vCard ayrıştırılamadı"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"Geçerli biçimde görünmesine rağmen vCard ayrıştırılamadı, çünkü şu anki uygulama vCard\'ı desteklemiyor"</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"SD kartta hiçbir vCard dosyası bulunamadı"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"Seçiminiz için geçerli vCard girdisi bulunamadı"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"İçe aktarılamayan bir veya birden fazla dosya (%s)."</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"Bilinmeyen hata"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"vCard dosyasını seç"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"Lütfen içe aktarılacak bir vCard dosyası seçin"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"vCard okunuyor"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"vCard dosyaları okunuyor"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"vCard verileri içe aktarılıyor"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"vCard verileri okunamadı"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"vCard okunamadı."\n"Hata nedeni: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"Toplam <xliff:g id="TOTAL_NUMBER">%s</xliff:g> kişiden <xliff:g id="CURRENT_NUMBER">%s</xliff:g>. kişi"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"toplam <xliff:g id="TOTAL_NUMBER">%s</xliff:g> dosyadan <xliff:g id="CURRENT_NUMBER">%s</xliff:g>. dosya"</string>
- <!-- no translation found for export_contact_list (3165097742175874384) -->
- <skip />
- <!-- no translation found for confirm_export_title (1693047909433122854) -->
- <skip />
- <!-- no translation found for confirm_export_message (63482084706768079) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_title (1455264422455075858) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_message (1426451081541603512) -->
- <skip />
- <!-- no translation found for fail_reason_too_many_vcard (5416992255233341607) -->
- <skip />
- <!-- no translation found for fail_reason_too_long_filename (7105223965196949065) -->
- <skip />
- <!-- no translation found for fail_reason_cannot_open_destination_dir (1739293936432987758) -->
- <skip />
- <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
- <skip />
- <!-- no translation found for exporting_contact_list_message (5640326540405486055) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_initialize_exporter (4943708332700987376) -->
- <skip />
- <!-- no translation found for fail_reason_error_occurred_during_export (2151165129433831202) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_open_file (4013520943128739511) -->
- <skip />
- <!-- no translation found for exporting_contact_list_progress (560522409559101193) -->
- <skip />
- <!-- no translation found for search_settings_description (2675223022992445813) -->
- <skip />
+ <string name="export_all_contacts" msgid="2873892623335194071">"Tüm kişiler"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"Yerel olarak depolanan kişiler"</string>
+ <string name="export_contact_list" msgid="3165097742175874384">"Kişileri dışa aktar"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"Dışa aktarımı onayla"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"Kişi listenizi \"<xliff:g id="VCARD_FILENAME">%s</xliff:g>\" için dışa aktarmak istediğinizden emin misiniz?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"Kişi verileri dışa aktarılamadı"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Kişi verileri dışa aktarılamadı."\n"Hata nedeni: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Dışa aktarılabilen hiçbir kişi yok"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"SD kartta çok fazla vCard dosyası var"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Gereken dosya adı çok uzun (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"\"<xliff:g id="DIR_NAME">%s</xliff:g>\" hedef dizini açılamıyor veya oluşturulamıyor"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Kişi verileri dışa aktarılıyor"</string>
+ <string name="exporting_contact_list_message" msgid="5640326540405486055">"Kişi verileri \"<xliff:g id="FILE_NAME">%s</xliff:g>\" dosyasına dışa aktarılıyor"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"Dışa aktarıcı başlatılamadı: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"Dışa aktarma sırasında hata oluştu: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"Veri tabanı bilgileri alınamadı"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"Dışa aktarılabilen hiçbir kişi yok. Dışa aktarılamayan veriler seçmiş olabilirsiniz"</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"vCard oluşturucu doğru bir şekilde başlatılmamış"</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" dosyası açılamadı: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_progress" msgid="560522409559101193">"Toplam <xliff:g id="TOTAL_NUMBER">%s</xliff:g> kişiden <xliff:g id="CURRENT_NUMBER">%s</xliff:g> kişi"</string>
+ <string name="search_settings_description" msgid="2675223022992445813">"Kişilerinizin adları"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"2 saniyelik duraklama ekle"</string>
+ <string name="add_wait" msgid="3360818652790319634">"Bekleme ekle"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"Çevir"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"Şu uygulamayı kullanarak ara"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"Şunu kullanarak SMS gönder:"</string>
+ <string name="make_primary" msgid="5829291915305113983">"Bu tercihi anımsa"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"Bu işlemi gerçekleştirecek bir uygulama bulunamadı"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"Bu tercihi anımsa"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"Bilinmiyor"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"Hesaplar"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"İçe/Dışa Aktar"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"Kişileri içe/dışa aktar"</string>
+ <string name="menu_share" msgid="943789700636542260">"Paylaş"</string>
+ <string name="share_via" msgid="563121028023030093">"Şu uygulamayı kullanarak kişi paylaş:"</string>
+ <string name="share_error" msgid="4374508848981697170">"Bu kişi paylaşılamıyor."</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Ad"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Takma ad"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Kuruluş"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Web sitesi"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"Etkinlik"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"E"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"M"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"İ"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"Ç"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"D"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"Bu kişi salt okunur"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"Diğer"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"Birincil ad"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"Hesap altında kişi oluştur"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Senkronize grubu kaldır"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Senk. grup ekle"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Diğer gruplar..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"Diğer Tüm Kişiler"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"Tüm Kişiler"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"\'<xliff:g id="GROUP">%s</xliff:g>\' grubunu senkronizasyondan kaldırmak, gruplandırılmamış tüm kişileri de senkronizasyondan kaldırır."</string>
+ <string name="account_phone" msgid="4025734638492419713">"Yalnızca telefon (senkronize edilmemiş)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"Adı görüntüle"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Ara (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="call_home" msgid="1990519474420545392">"Evi ara"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Mobil cihazı ara"</string>
+ <string name="call_work" msgid="5328785911463744028">"Ara (iş)"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Ara (iş faksı)"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Ara (ev faksı)"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Çağrı cihazını ara"</string>
+ <string name="call_other" msgid="5605584621798108205">"Ara (diğer)"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Çağrı: (geri arama)"</string>
+ <string name="call_car" msgid="3280537320306436445">"Ara (araç)"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Ara (şirket merkezi)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Çağrı: (ISDN)"</string>
+ <string name="call_main" msgid="6082900571803441339">"Çağrı: (ana hat)"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"Çağrı: (diğer faks)"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Ara (telsiz)"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Çağrı: (teleks)"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Çağrı: TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Çağrı: (iş yeri cep telefonu)"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Çağrı: (iş yeri çağrı cihazı)"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Çağrı: <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Ara (MMS)"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"Metin <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"SMS gönder (ev)"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"SMS gönder (mobil)"</string>
+ <string name="sms_work" msgid="2269624156655267740">"SMS gönder (iş)"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"SMS gönder (iş faksı)"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"SMS gönder (ev faksı)"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"SMS gönder (çağrı cihazı)"</string>
+ <string name="sms_other" msgid="5131921487474531617">"SMS gönder (diğer)"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"SMS Gönder (geri arama)"</string>
+ <string name="sms_car" msgid="7444227058437359641">"SMS gönder (araç)"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"SMS gönder (şirket merkezi)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"SMS Gönder (ISDN)"</string>
+ <string name="sms_main" msgid="8621625784504541679">"SMS Gönder (ana hat)"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"SMS Gönder (diğer faks)"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"SMS gönder (telsiz)"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"SMS Gönder (teleks)"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"SMS Gönder (TTY/TDD)"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"SMS Gönder (iş yeri cep telefonu)"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"SMS Gönder (iş yeri çağrı cihazı)"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"SMS Gönder (<xliff:g id="ASSISTANT">%s</xliff:g>)"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"SMS gönder (MMS)"</string>
+ <string name="email_home" msgid="8573740658148184279">"E-posta gönder (ev)"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-posta gönder (mobil)"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-posta gönder (iş)"</string>
+ <string name="email_other" msgid="8093933498541795832">"E-posta gönder (diğer)"</string>
+ <string name="email_custom" msgid="7548003991586214105">"E-posta <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-posta"</string>
+ <string name="map_home" msgid="1243547733423343982">"Ev adresini görüntüle"</string>
+ <string name="map_work" msgid="1360474076921878088">"İş adresini görüntüle"</string>
+ <string name="map_other" msgid="5560707927535653892">"Diğer adresi görüntüle"</string>
+ <string name="map_custom" msgid="6184363799976265281">"<xliff:g id="CUSTOM">%s</xliff:g> adresini görüntüle"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"AIM kullanarak sohbet et"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Windows Live kullanarak sohbet et"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Yahoo kullanarak sohbet et"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Skype kullanarak sohbet et"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"QQ kullanarak sohbet et"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Google Talk kullanarak sohbet et"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"ICQ kullanarak sohbet et"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Jabber kullanarak sohbet et"</string>
+ <string name="chat" msgid="9025361898797412245">"Sohbet"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Cadde"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Posta kutusu"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Mahalle"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Şehir"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Eyalet"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Alan kodu"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Ülke"</string>
+ <string name="name_given" msgid="1687286314106019813">"Vaftiz adı"</string>
+ <string name="name_family" msgid="3416695586119999058">"Soyadı"</string>
+ <string name="name_prefix" msgid="59756378548779822">"Ad öneki"</string>
+ <string name="name_middle" msgid="8467433655992690326">"İkinci ad"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Ad soneki"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"Fonetik vaftiz adı"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetik ikinci ad"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"Fonetik soyadı"</string>
+ <string name="split_label" msgid="8262112659919449087">"Ayır"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"Bu veriyi kendi kişisi haline getirin."</string>
+ <string name="account_name_format" msgid="4421123930035299208">"<xliff:g id="SOURCE">%1$s</xliff:g> hesabından: <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> kişi"</string>
+ <string name="from_account_format" msgid="687567483928582084">"kaynak: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"Bu fotoğrafı kullan"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> kişi bilgileri bu cihazda düzenlenemez."</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"Bu kişi için ek bilgi yok"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 38154e1..fee1bf9 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -16,18 +16,13 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"联系人"</string>
- <string name="launcherDialer" msgid="140610573639849799">"拨号"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"手机"</string>
<string name="shortcutContact" msgid="749243779392912958">"联系人"</string>
- <!-- no translation found for shortcutDialContact (7165340343023469996) -->
- <skip />
- <!-- no translation found for shortcutMessageContact (3025782962770298900) -->
- <skip />
- <!-- no translation found for shortcutActivityTitle (6642877210643565436) -->
- <skip />
- <!-- no translation found for callShortcutActivityTitle (6065749861423648991) -->
- <skip />
- <!-- no translation found for messageShortcutActivityTitle (3084542316620335911) -->
- <skip />
+ <string name="shortcutDialContact" msgid="746622101599186779">"直接拨打"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"直接发送短信"</string>
+ <string name="shortcutActivityTitle" msgid="6642877210643565436">"选择联系人快捷方式"</string>
+ <string name="callShortcutActivityTitle" msgid="6065749861423648991">"选择一个可直接拨号的号码"</string>
+ <string name="messageShortcutActivityTitle" msgid="3084542316620335911">"选择一个可直接向其发送短信的号码"</string>
<string name="starredList" msgid="4817256136413959463">"已加星标"</string>
<string name="frequentList" msgid="7154768136473953056">"频繁"</string>
<string name="strequentList" msgid="5640192862059373511">"收藏"</string>
@@ -41,16 +36,37 @@
<string name="menu_viewContact" msgid="2795575601596468581">"查看联系人"</string>
<string name="menu_callNumber" msgid="5142851348489387516">"呼叫<xliff:g id="NAME">%s</xliff:g>"</string>
<string name="menu_addStar" msgid="2908478235715404876">"添加到收藏"</string>
- <string name="menu_removeStar" msgid="5844227078364227030">"从收藏删除"</string>
+ <string name="menu_removeStar" msgid="5844227078364227030">"从收藏中删除"</string>
<string name="menu_showBarcode" msgid="309973637178814132">"显示条形码"</string>
<string name="menu_editContact" msgid="3452858480713561396">"编辑联系人"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"删除联系人"</string>
- <string name="menu_call" msgid="7359207953236681606">"呼叫"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"发送短信/彩信"</string>
+ <string name="menu_call" msgid="3992595586042260618">"呼叫联系人"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"向联系人发送短信"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"发送电子邮件"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"地图地址"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"设置默认号码"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"设置为默认电子邮件"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"拆分"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"分离联系人"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"已拆分联系人"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"拆分联系人"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"您确定要将此单一联系人拆分为多位联系人(即,其中包含的每条联系信息分别对应一位联系人)吗?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"合并"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"显示来源"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"隐藏来源"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"合并联系人"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"合并联系人"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"选择要与<xliff:g id="NAME">%s</xliff:g>合并的联系人。"</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"显示所有联系人"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"建议的联系人"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"所有联系人"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"已合并联系人"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"选项"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"选项"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"删除"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"您不能删除只读帐户中的联系人,但可以在您的联系人列表中将其隐藏。"</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"该联系人的信息中包含来自多个帐户的信息。来自只读帐户的信息将在您的联系人列表中隐藏,但不会删除。"</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"删除该联系人将会删除多个帐户中的信息。"</string>
<string name="deleteConfirmation" msgid="811706994761610640">"将会删除此联系人。"</string>
<string name="menu_done" msgid="796017761764190697">"完成"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"还原"</string>
@@ -60,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"拼音"</string>
<string name="label_notes" msgid="8337354953278341042">"备注"</string>
<string name="label_ringtone" msgid="8833166825330686244">"铃声"</string>
+ <string name="label_groups" msgid="7304551384542859026">"群组"</string>
+ <string name="group_list" msgid="8583361685440161307">"、<xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"编辑群组"</string>
<string name="ghostData_name" msgid="6490954238641157585">"姓名"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"姓名拼音"</string>
<string name="ghostData_company" msgid="5414421120553765775">"公司"</string>
@@ -69,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"电话号码"</string>
<string name="ghostData_email" msgid="6184537075551565919">"电子邮件地址"</string>
<string name="ghostData_postal" msgid="652611650594951897">"邮政地址"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"显示群组"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"联系人不存在。"</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"新建联系人"</string>
<string name="selectLabel" msgid="4255424123394910733">"选择标签"</string>
@@ -85,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"手机上没有图片。"</string>
<string name="attachToContact" msgid="8820530304406066714">"联系人图标"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"自定义标签名称"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"显示群组"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"显示选项"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"显示选项"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"编辑同步群组"</string>
<string name="importFromSim" msgid="8383900146531125319">"导入联系人"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"直接将呼叫发送到语音信箱"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"呼叫直接发送到语音信箱。"</string>
<string name="default_ringtone" msgid="9099988849649827972">"默认"</string>
<string name="addPicture" msgid="1594679312161537678">"添加图标"</string>
+ <string name="changePicture" msgid="2943329047610967714">"更改图标"</string>
<string name="removePicture" msgid="3041230993155966350">"删除图标"</string>
<string name="noContacts" msgid="8579310973261953559">"无联系人。"</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"未找到匹配的联系人。"</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"无具有手机号码的联系人。"</string>
<string name="noFavorites" msgid="812766386743315815">"无收藏。"</string>
<string name="select_group_title" msgid="7955698611959835612">"群组"</string>
<string name="groupEmpty" msgid="6661950109828194595">"“<xliff:g id="GROUPNAME">%s</xliff:g>”群组为空。"</string>
<string name="showAllGroups" msgid="5164410117611094297">"所有联系人"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"仅显示有电话号码的联系人"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"仅显示有电话号码的联系人"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"选择要显示的联系人"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> 位联系人"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"共 <xliff:g id="COUNT_0">%1$d</xliff:g> 位联系人,其中 <xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> 位有电话号码"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"同步所有联系人"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"我的联系人"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"我的联系人"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"具有手机号码的联系人"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"Android 中加星标的联系人"</string>
+ <string name="savingContact" msgid="4075751076741924939">"正在保存联系人…"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"正在保存显示选项…"</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"已创建联系人。"</string>
<string name="contactSavedToast" msgid="7152589189385441091">"联系人已保存。"</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"发生错误,无法保存联系人更改。"</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"拨打电话"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"电话号码"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"发送短信/彩信"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"发送文本"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"发送电子邮件"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"电子邮件地址"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"发送即时消息"</string>
@@ -115,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"地图地址"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"邮政地址"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"组织"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"群组"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"其他信息"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"其他选项"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"更多"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"显示 1 位有电话号码的联系人"</item>
+ <item quantity="other" msgid="6133262880804110289">"显示 <xliff:g id="COUNT">%d</xliff:g> 位有电话号码的联系人"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"显示的联系人都没有电话号码。"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"显示 1 位联系人"</item>
+ <item quantity="other" msgid="2865867557378939630">"显示 <xliff:g id="COUNT">%d</xliff:g> 位联系人"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"未显示任何联系人"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"找到 1 位联系人"</item>
+ <item quantity="other" msgid="7752927996850263152">"找到 <xliff:g id="COUNT">%d</xliff:g> 位联系人"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"未找到联系人"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"社交"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"联系人"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"收藏"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"拨号器"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"手机"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"通话记录"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"所有联系人"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"已加星标的联系人"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"具有手机号码的联系人"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"发送短信"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"发送短信"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"呼叫<xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"在呼叫前编辑号码"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"添加到联系人"</string>
@@ -133,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"清除通话记录"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"通话记录为空。"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"语音信箱"</string>
<string name="unknown" msgid="740067747858270469">"未知"</string>
<string name="private_num" msgid="6374339738119166953">"私人号码"</string>
@@ -142,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"正在从 SIM 卡载入..."</string>
<string name="simContacts_title" msgid="27341688347689769">"SIM 卡联系人"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">"同步您的 Google 联系人!"</font>" "\n"将您的联系人同步到您的手机,然后您在任何地方都可以与他们联系。"</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"您没有任何联系人。"\n\n"要添加联系人,请按 "<font fgcolor="#ffffffff"><b>"MENU"</b></font>" 并选择:"\n" "\n<li><font fgcolor="#ffffffff"><b>"新建联系人"</b></font>"以从头开始创建新联系人 "\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"导入联系人"</b></font>"以从您的 SIM 卡添加联系人"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"您没有任何联系人。"\n\n"要添加联系人,请按 "<font fgcolor="#ffffffff"><b>"MENU"</b></font>" 并选择:"\n" "\n<li><font fgcolor="#ffffffff"><b>"编辑同步群组"</b></font>"以从新的或现有的 Google 帐户添加"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"新建联系人"</b></font>"以从头开始创建新联系人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"导入联系人"</b></font>"以从您的 SIM 卡添加联系人"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"您没有可显示的联系人。"\n\n"要添加联系人,请按"<font fgcolor="#ffffffff"><b>"菜单"</b></font>",然后触摸:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Google 帐户"</b></font>"以添加或配置可同步到手机的联系人的帐户"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"新建联系人"</b></font>"以从头开始创建新联系人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"导入/导出"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"您没有可显示的联系人。(如果您刚刚添加了一个帐户,则需要几分钟时间同步联系人。)"\n\n"要添加联系人,请按"<font fgcolor="#ffffffff"><b>"菜单"</b></font>",然后触摸:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Google 帐户"</b></font>"以添加或配置可同步到手机的联系人的帐户"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"显示选项"</b></font>"以更改可见的联系人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"新建联系人"</b></font>"以从头开始创建新联系人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"导入/导出"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"您没有可显示的联系人。"\n\n"要添加联系人,请按"<font fgcolor="#ffffffff"><b>"菜单"</b></font>",然后触摸:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Google 帐户"</b></font>"以添加或配置可同步到手机的联系人的帐户"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"新建联系人"</b></font>"以从头开始创建新联系人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"导入/导出"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"您没有可显示的联系人。(如果您刚刚添加了一个帐户,则需要几分钟时间同步联系人。)"\n\n"要添加联系人,请按"<font fgcolor="#ffffffff"><b>"菜单"</b></font>",然后触摸:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Google 帐户"</b></font>"以添加或配置可同步到手机的联系人的帐户"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"显示选项"</b></font>"以更改可见的联系人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"新建联系人"</b></font>"以从头开始创建新联系人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"导入/导出"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"您未收藏任何内容。"\n\n"要向您的收藏列表添加联系人,请执行以下操作:"\n\n" "<li>"触摸"<b>"联系人"</b>"标签"\n</li>\n<li>"触摸您要加入收藏的联系人"\n</li>\n<li>"触摸联系人姓名旁边的星标"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"选择要同步的群组"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"所有联系人"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"所有联系人"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"已加星标"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"手机"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"使用按键式数字键盘"</string>
@@ -155,7 +211,7 @@
<string name="toast_call_detail_error" msgid="7200975244804730096">"无法读取所请求呼叫的详细信息。"</string>
<string name="call_type" msgid="3213526349444862087">"类型"</string>
<string name="type_incoming" msgid="6502076603836088532">"来电"</string>
- <string name="type_outgoing" msgid="343108709599392641">"对外呼叫"</string>
+ <string name="type_outgoing" msgid="343108709599392641">"外拨电话"</string>
<string name="type_missed" msgid="2720502601640509542">"未接电话"</string>
<string name="call_time" msgid="5805575214626630975">"时间"</string>
<string name="datetime_relative" msgid="2906207446040994658">"<xliff:g id="DATETIME">%1$s</xliff:g> (<xliff:g id="RELATIVE">%2$s</xliff:g>)"</string>
@@ -167,93 +223,200 @@
<string name="actionEmail" msgid="3870371552333656807">"发送电子邮件至<xliff:g id="TYPE">%s</xliff:g>"</string>
<string name="actionText" msgid="6399049224844880108">"发送信息至<xliff:g id="TYPE">%s</xliff:g>"</string>
<string name="actionChat" msgid="31079429748650300">"使用<xliff:g id="TYPE">%s</xliff:g>聊天"</string>
- <string name="actionMap" msgid="1977955782051732775">"查看<xliff:g id="TYPE">%s</xliff:g>地址"</string>
+ <string name="actionMap" msgid="1977955782051732775">"查看<xliff:g id="TYPE">%s</xliff:g>"</string>
<string name="actionIncomingCall" msgid="6028930669817038600">"来电"</string>
<string name="detailIncomingCallsGoToVoicemail" msgid="9163373178772231307">"直接发送到语音信箱"</string>
<string name="detailsRingtone" msgid="4052108748982701775">"设为<xliff:g id="RINGTONE_NAME">%s</xliff:g>"</string>
<string name="callBack" msgid="5498224409038809224">"回电"</string>
- <string name="callAgain" msgid="3197312117049874778">"重新呼叫"</string>
- <string name="returnCall" msgid="8171961914203617813">"返回呼叫"</string>
+ <string name="callAgain" msgid="3197312117049874778">"重拨"</string>
+ <string name="returnCall" msgid="8171961914203617813">"回拨"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> 分 <xliff:g id="SECONDS">%s</xliff:g> 秒"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"经常呼叫"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"添加联系人"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"添加联系人"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"将“<xliff:g id="EMAIL">%s</xliff:g>”添加到联系人?"</string>
- <!-- no translation found for description_image_button_one (1740638037139856139) -->
- <skip />
- <!-- no translation found for description_image_button_two (5882638439003731308) -->
- <skip />
- <!-- no translation found for description_image_button_three (8709731759376015180) -->
- <skip />
- <!-- no translation found for description_image_button_four (3530239685642246130) -->
- <skip />
- <!-- no translation found for description_image_button_five (1182465427501188413) -->
- <skip />
- <!-- no translation found for description_image_button_six (2093656269261415475) -->
- <skip />
- <!-- no translation found for description_image_button_seven (2450357020447676481) -->
- <skip />
- <!-- no translation found for description_image_button_eight (6969435115163287801) -->
- <skip />
- <!-- no translation found for description_image_button_nine (7857248695662558323) -->
- <skip />
- <!-- no translation found for description_image_button_star (3365919907520767866) -->
- <skip />
- <!-- no translation found for description_image_button_zero (4133108949401820710) -->
- <skip />
- <!-- no translation found for description_image_button_pound (3039765597595889230) -->
- <skip />
- <string name="no_sdcard_title" msgid="6455416795090113715">"无 SD 卡"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"未检测到 SD 卡"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"正在搜索 VCard"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"全部"</string>
+ <string name="description_image_button_one" msgid="1740638037139856139">"一"</string>
+ <string name="description_image_button_two" msgid="5882638439003731308">"二"</string>
+ <string name="description_image_button_three" msgid="8709731759376015180">"三"</string>
+ <string name="description_image_button_four" msgid="3530239685642246130">"四"</string>
+ <string name="description_image_button_five" msgid="1182465427501188413">"五"</string>
+ <string name="description_image_button_six" msgid="2093656269261415475">"六"</string>
+ <string name="description_image_button_seven" msgid="2450357020447676481">"七"</string>
+ <string name="description_image_button_eight" msgid="6969435115163287801">"八"</string>
+ <string name="description_image_button_nine" msgid="7857248695662558323">"九"</string>
+ <string name="description_image_button_star" msgid="3365919907520767866">"星形符号"</string>
+ <string name="description_image_button_zero" msgid="4133108949401820710">"零"</string>
+ <string name="description_image_button_pound" msgid="3039765597595889230">"英镑符号"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"无 SD 卡"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"未检测到 SD 卡"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"正在搜索 vCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"您希望从何处导入联系人?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIM 卡"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"SD 卡"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"导入所有 VCard 文件"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"导入一个 VCard 文件"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"正在搜索 VCard 上的 VCard 数据"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"扫描 SD 卡失败"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"扫描 SD 卡失败"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"从 SIM 卡导入"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"从 SD 卡导入"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"导出到 SD 卡"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"导入一个 vCard 文件"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"导入多个 vCard 文件"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"导入所有 vCard 文件"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"正在 SD 卡中搜索 vCard 数据"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"扫描 SD 卡失败"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"扫描 SD 卡失败(原因:“<xliff:g id="FAIL_REASON">%s</xliff:g>”)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O 错误"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"解析 VCard 失败"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"未在 SD 卡上找到 VCard 文件"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"未找到与所选内容对应的有效 VCard 条目"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"选择 VCard 文件"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"请选择要导入的 VCard 文件"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"正在读取 VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"正在读取 VCard 文件"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"正在导入 VCard 数据"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"读取 VCard 数据失败"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"无法读取 VCard 数据"\n"失败原因:“<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"由于意外原因而无法解析 vCard"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"虽然 vCard 似乎使用了有效的格式,但系统无法对其进行解析,因为当前的实现方案不支持该格式。"</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"未在 SD 卡上找到 vCard 文件"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"未找到与所选内容对应的有效 vCard 条目"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"一个或多个文件导入失败 (%s)。"</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"未知错误"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"选择 vCard 文件"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"请选择要导入的 vCard 文件"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"正在读取 vCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"正在读取 vCard 文件"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"正在导入 vCard 数据"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"读取 vCard 数据失败"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"无法读取 vCard。"\n"失败原因:“<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"第 <xliff:g id="CURRENT_NUMBER">%s</xliff:g> 个,共 <xliff:g id="TOTAL_NUMBER">%s</xliff:g> 个联系人"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"第 <xliff:g id="CURRENT_NUMBER">%s</xliff:g> 个,共 <xliff:g id="TOTAL_NUMBER">%s</xliff:g> 个文件"</string>
- <!-- no translation found for export_contact_list (3165097742175874384) -->
- <skip />
- <!-- no translation found for confirm_export_title (1693047909433122854) -->
- <skip />
- <!-- no translation found for confirm_export_message (63482084706768079) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_title (1455264422455075858) -->
- <skip />
- <!-- no translation found for exporting_contact_failed_message (1426451081541603512) -->
- <skip />
- <!-- no translation found for fail_reason_too_many_vcard (5416992255233341607) -->
- <skip />
- <!-- no translation found for fail_reason_too_long_filename (7105223965196949065) -->
- <skip />
- <!-- no translation found for fail_reason_cannot_open_destination_dir (1739293936432987758) -->
- <skip />
- <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
- <skip />
- <!-- no translation found for exporting_contact_list_message (5640326540405486055) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_initialize_exporter (4943708332700987376) -->
- <skip />
- <!-- no translation found for fail_reason_error_occurred_during_export (2151165129433831202) -->
- <skip />
- <!-- no translation found for fail_reason_could_not_open_file (4013520943128739511) -->
- <skip />
- <!-- no translation found for exporting_contact_list_progress (560522409559101193) -->
- <skip />
- <!-- no translation found for search_settings_description (2675223022992445813) -->
- <skip />
+ <string name="export_all_contacts" msgid="2873892623335194071">"所有联系人"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"本地存储的联系人"</string>
+ <string name="export_contact_list" msgid="3165097742175874384">"导出联系人"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"确认导出"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"确定要将您的联系人列表导出到“<xliff:g id="VCARD_FILENAME">%s</xliff:g>”中吗?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"导出联系人数据失败"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"导出联系人数据失败。"\n"失败原因:“<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"没有可导出的联系人"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"SD 卡中的 vCard 文件太多"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"所需文件名太长(“<xliff:g id="FILENAME">%s</xliff:g>”)"</string>
+ <string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"无法打开或创建目标目录“<xliff:g id="DIR_NAME">%s</xliff:g>”"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"正在导出联系人数据"</string>
+ <string name="exporting_contact_list_message" msgid="5640326540405486055">"正在向“<xliff:g id="FILE_NAME">%s</xliff:g>”导出联系人数据"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"无法初始化导出程序:“<xliff:g id="EXACT_REASON">%s</xliff:g>”"</string>
+ <string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"导出时出错:“<xliff:g id="EXACT_REASON">%s</xliff:g>”"</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"获取数据库信息失败"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"没有可导出的联系人。您可能选择了无法导出的数据。"</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"vCard 制作程序未正确初始化"</string>
+ <string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"无法打开“<xliff:g id="FILE_NAME">%s</xliff:g>”:<xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_progress" msgid="560522409559101193">"第 <xliff:g id="CURRENT_NUMBER">%s</xliff:g> 个联系人(共 <xliff:g id="TOTAL_NUMBER">%s</xliff:g> 个)"</string>
+ <string name="search_settings_description" msgid="2675223022992445813">"联系人姓名"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"暂停时间延长 2 秒"</string>
+ <string name="add_wait" msgid="3360818652790319634">"延长等待时间"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"拨打"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"呼叫方式"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"短信发送方式"</string>
+ <string name="make_primary" msgid="5829291915305113983">"记住此选择"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"未找到可处理此操作的应用程序"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"记住此选择"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"未知"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"帐户"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"导入/导出"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"导入/导出联系人"</string>
+ <string name="menu_share" msgid="943789700636542260">"分享"</string>
+ <string name="share_via" msgid="563121028023030093">"联系人分享方式"</string>
+ <string name="share_error" msgid="4374508848981697170">"无法分享此联系人。"</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"名称"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"昵称"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"组织"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"网站"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"活动"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"住宅"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"手机"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"单位"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"寻呼"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"其他"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"该联系人的状态为只读"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"更多"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"主名称"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"在帐户下创建联系人"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"删除同步群组"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"添加同步群组"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"更多群组…"</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"其他所有联系人"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"所有联系人"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"如果从同步中删除群组“<xliff:g id="GROUP">%s</xliff:g>”,则会同时删除其中所有未分组的联系人。"</string>
+ <string name="account_phone" msgid="4025734638492419713">"仅保存在手机中(不同步)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"显示名称"</string>
+ <string name="call_custom" msgid="7756571794763171802">"呼叫<xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"呼叫住宅"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"呼叫手机"</string>
+ <string name="call_work" msgid="5328785911463744028">"呼叫单位"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"呼叫单位传真"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"呼叫住宅传真"</string>
+ <string name="call_pager" msgid="9003902812293983281">"呼叫寻呼机"</string>
+ <string name="call_other" msgid="5605584621798108205">"呼叫其他号码"</string>
+ <string name="call_callback" msgid="1910165691349426858">"呼叫回拨号码"</string>
+ <string name="call_car" msgid="3280537320306436445">"呼叫车载电话"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"呼叫公司总机"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"呼叫 ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"呼叫总机"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"呼叫其他传真"</string>
+ <string name="call_radio" msgid="8296755876398357063">"呼叫无线装置"</string>
+ <string name="call_telex" msgid="2223170774548648114">"呼叫电报"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"呼叫 TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"呼叫单位手机"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"呼叫单位寻呼机"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"呼叫<xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"呼叫彩信号码"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"向<xliff:g id="CUSTOM">%s</xliff:g>发送文本消息"</string>
+ <string name="sms_home" msgid="7524332261493162995">"向住宅发送文本消息"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"向手机发送文本消息"</string>
+ <string name="sms_work" msgid="2269624156655267740">"向单位发送文本消息"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"向单位传真发送文本消息"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"向住宅传真发送文本消息"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"向寻呼机发送文字消息"</string>
+ <string name="sms_other" msgid="5131921487474531617">"向其他手机号码发送文本消息"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"向回拨号码发送短信"</string>
+ <string name="sms_car" msgid="7444227058437359641">"向车载电话发送文本消息"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"向公司总机发送文本消息"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"向 ISDN 发送短信"</string>
+ <string name="sms_main" msgid="8621625784504541679">"向总机发送短信"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"向其他传真发送短信"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"向无线装置发送文本消息"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"向电报发送短信"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"向 TTY/TDD 发送短信"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"向单位手机发送短信"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"向单位寻呼机发送短信"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"向<xliff:g id="ASSISTANT">%s</xliff:g>发送短信"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"向彩信号码发送文本消息"</string>
+ <string name="email_home" msgid="8573740658148184279">"向住宅发送电子邮件"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"向手机发送电子邮件"</string>
+ <string name="email_work" msgid="2807430017302722689">"向单位发送电子邮件"</string>
+ <string name="email_other" msgid="8093933498541795832">"向其他地址发送电子邮件"</string>
+ <string name="email_custom" msgid="7548003991586214105">"向<xliff:g id="CUSTOM">%s</xliff:g>发送电子邮件"</string>
+ <string name="email" msgid="5668400997660065897">"电子邮件"</string>
+ <string name="map_home" msgid="1243547733423343982">"查看住宅地址"</string>
+ <string name="map_work" msgid="1360474076921878088">"查看单位地址"</string>
+ <string name="map_other" msgid="5560707927535653892">"查看其他地址"</string>
+ <string name="map_custom" msgid="6184363799976265281">"查看<xliff:g id="CUSTOM">%s</xliff:g>地址"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"使用 AIM 聊天"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"使用 Windows Live 聊天"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"使用雅虎软件聊天"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"使用 Skype 聊天"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"使用 QQ 聊天"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"使用 Google Talk 聊天"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"使用 ICQ 聊天"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"使用 Jabber 聊天"</string>
+ <string name="chat" msgid="9025361898797412245">"聊天"</string>
+ <string name="postal_street" msgid="8133143961580058972">"街道"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"信箱"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"街区"</string>
+ <string name="postal_city" msgid="6597491300084895548">"城市"</string>
+ <string name="postal_region" msgid="6045263193478437672">"省/直辖市/自治区"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"邮政编码"</string>
+ <string name="postal_country" msgid="7638264508416368690">"国家/地区"</string>
+ <string name="name_given" msgid="1687286314106019813">"名字"</string>
+ <string name="name_family" msgid="3416695586119999058">"姓氏"</string>
+ <string name="name_prefix" msgid="59756378548779822">"名称前缀"</string>
+ <string name="name_middle" msgid="8467433655992690326">"中间名"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"名称后缀"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"名字拼音"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"中间名拼音"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"姓氏拼音"</string>
+ <string name="split_label" msgid="8262112659919449087">"分离"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"使数据各归其主。"</string>
+ <string name="account_name_format" msgid="4421123930035299208">"来自<xliff:g id="SOURCE">%1$s</xliff:g>帐户:<xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> 联系人"</string>
+ <string name="from_account_format" msgid="687567483928582084">"来自 <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"使用此照片"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"<xliff:g id="SOURCE">%1$s</xliff:g> 联系人信息在此设备上不可编辑。"</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"无此联系人的其他信息"</string>
</resources>
diff --git a/res/values-zh-rTW/config.xml b/res/values-zh-rTW/config.xml
deleted file mode 100644
index 07b3c7e..0000000
--- a/res/values-zh-rTW/config.xml
+++ /dev/null
@@ -1,28 +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">
- <!-- no translation found for config_export_vcard_type (9145748078116159716) -->
- <skip />
- <string name="config_export_dir" msgid="222182743639478636">"/sdcard"</string>
- <!-- no translation found for config_export_file_prefix (3022868431158658122) -->
- <skip />
- <!-- no translation found for config_export_file_suffix (16505844221142195) -->
- <skip />
- <string name="config_export_file_extension" msgid="1758878818611339161">"vcf"</string>
- <!-- no translation found for config_export_extensions_to_consider (5095044502091950623) -->
- <skip />
-</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index c980084..601583a 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -16,10 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="contactsList" msgid="8661624236494819731">"聯絡人"</string>
- <string name="launcherDialer" msgid="140610573639849799">"撥號"</string>
+ <string name="launcherDialer" msgid="8636288196618486553">"電話"</string>
<string name="shortcutContact" msgid="749243779392912958">"聯絡人"</string>
- <string name="shortcutDialContact" msgid="7165340343023469996">"直接撥號"</string>
- <string name="shortcutMessageContact" msgid="3025782962770298900">"直接傳訊"</string>
+ <string name="shortcutDialContact" msgid="746622101599186779">"直接撥號"</string>
+ <string name="shortcutMessageContact" msgid="2460337253595976198">"直接傳訊"</string>
<string name="shortcutActivityTitle" msgid="6642877210643565436">"選擇聯絡人捷徑"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"選擇去電號碼"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"選擇傳訊號碼"</string>
@@ -40,12 +40,33 @@
<string name="menu_showBarcode" msgid="309973637178814132">"顯示條碼"</string>
<string name="menu_editContact" msgid="3452858480713561396">"編輯聯絡人"</string>
<string name="menu_deleteContact" msgid="1916555454274101750">"刪除聯絡人"</string>
- <string name="menu_call" msgid="7359207953236681606">"通話"</string>
- <string name="menu_sendSMS" msgid="5917289601666766617">"傳送 SMS/MMS"</string>
+ <string name="menu_call" msgid="3992595586042260618">"去電聯絡人"</string>
+ <string name="menu_sendSMS" msgid="5535886767547006515">"傳送簡訊至聯絡人"</string>
<string name="menu_sendEmail" msgid="7293508859242926187">"傳送電子郵件"</string>
<string name="menu_viewAddress" msgid="1814744325763202024">"在地圖上顯示地址"</string>
<string name="menu_makeDefaultNumber" msgid="4838759253316649534">"設為預設號碼"</string>
+ <string name="menu_makeDefaultEmail" msgid="2599044610375789994">"設為預設電子郵件"</string>
+ <string name="menu_splitAggregate" msgid="8368636463748691868">"分割"</string>
+ <string name="splitAggregate_title" msgid="2053462872948058798">"分割聯絡人"</string>
+ <string name="contactsSplitMessage" msgid="5253490235863170269">"已分割的聯絡人"</string>
+ <string name="splitConfirmation_title" msgid="6716467920283502570">"分割聯絡人"</string>
+ <string name="splitConfirmation" msgid="1150797297503944823">"您確定要將這個聯絡人分割成多組聯絡資訊嗎 (個別分到相關的聯絡資訊分類)?"</string>
+ <string name="menu_joinAggregate" msgid="5027981918265667970">"合併"</string>
+ <string name="menu_showSources" msgid="885215611438295455">"顯示來源"</string>
+ <string name="menu_hideSources" msgid="71367585820555477">"隱藏來源"</string>
+ <string name="titleJoinAggregate" msgid="6970566008563147202">"合併聯絡人"</string>
+ <string name="titleJoinContactDataWith" msgid="7684875775798635354">"合併聯絡人"</string>
+ <string name="blurbJoinContactDataWith" msgid="995870557595050304">"選取要與<xliff:g id="NAME">%s</xliff:g>合併的聯絡人。"</string>
+ <string name="showAllContactsJoinItem" msgid="2189695051430392383">"顯示所有聯絡人"</string>
+ <string name="separatorJoinAggregateSuggestions" msgid="2831414448851313345">"建議聯絡人"</string>
+ <string name="separatorJoinAggregateAll" msgid="7939932265026181043">"所有聯絡人"</string>
+ <string name="contactsJoinedMessage" msgid="7208148163607047389">"已合併聯絡人"</string>
+ <string name="menu_contactOptions" msgid="1957061455705020617">"選項"</string>
+ <string name="contactOptionsTitle" msgid="8259347644090700915">"選項"</string>
<string name="deleteConfirmation_title" msgid="6394309508930335204">"刪除"</string>
+ <string name="readOnlyContactWarning" msgid="1390849295342594265">"您無法從唯讀帳戶中刪除聯絡人,但可在您的聯絡人清單中隱藏他們。"</string>
+ <string name="readOnlyContactDeleteConfirmation" msgid="2137170726670196909">"此聯絡人包含來自多個帳戶的資訊。您的聯絡人清單不會顯示唯讀帳戶的資訊 (這些資訊並不會被刪除)。"</string>
+ <string name="multipleContactDeleteConfirmation" msgid="938900978442960800">"刪除此聯絡人將會刪除多個帳戶的資訊。"</string>
<string name="deleteConfirmation" msgid="811706994761610640">"刪除此聯絡人?"</string>
<string name="menu_done" msgid="796017761764190697">"完成"</string>
<string name="menu_doNotSave" msgid="2174577548513895144">"取消"</string>
@@ -55,6 +76,9 @@
<string name="label_phonetic_name" msgid="2288082649573927286">"拼音"</string>
<string name="label_notes" msgid="8337354953278341042">"附註"</string>
<string name="label_ringtone" msgid="8833166825330686244">"鈴聲"</string>
+ <string name="label_groups" msgid="7304551384542859026">"群組"</string>
+ <string name="group_list" msgid="8583361685440161307">"、<xliff:g id="GROUPNAME">%s</xliff:g>"</string>
+ <string name="menu_viewGroup" msgid="1401851715586577551">"編輯群組"</string>
<string name="ghostData_name" msgid="6490954238641157585">"姓名"</string>
<string name="ghostData_phonetic_name" msgid="7852749081984070902">"姓名拼音"</string>
<string name="ghostData_company" msgid="5414421120553765775">"公司"</string>
@@ -64,6 +88,7 @@
<string name="ghostData_phone" msgid="6963153888271466620">"電話號碼"</string>
<string name="ghostData_email" msgid="6184537075551565919">"電子郵件地址"</string>
<string name="ghostData_postal" msgid="652611650594951897">"郵寄地址"</string>
+ <string name="ghostData_group" msgid="4504591380347534114">"顯示群組"</string>
<string name="invalidContactMessage" msgid="5816991830260044593">"聯絡人不存在。"</string>
<string name="pickerNewContactHeader" msgid="7750705279843568147">"建立新聯絡人"</string>
<string name="selectLabel" msgid="4255424123394910733">"選取標籤"</string>
@@ -80,29 +105,44 @@
<string name="photoPickerNotFoundText" msgid="431331662154342581">"手機上沒有相片 。"</string>
<string name="attachToContact" msgid="8820530304406066714">"聯絡人圖示"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"自訂標籤名稱"</string>
- <string name="menu_displayGroup" msgid="4603480747214476335">"顯示群組"</string>
+ <string name="menu_displayGroup" msgid="5655505437727616553">"顯示選項"</string>
+ <string name="displayGroups" msgid="2278964020773993336">"顯示選項"</string>
<string name="syncGroupPreference" msgid="9028361137161162861">"編輯同步處理群組"</string>
<string name="importFromSim" msgid="8383900146531125319">"匯入聯絡人"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"直接將來電轉到語音信箱"</string>
<string name="send_to_voicemail_view" msgid="9124400414311776864">"來電已直接轉至語音信箱。"</string>
<string name="default_ringtone" msgid="9099988849649827972">"預設值"</string>
<string name="addPicture" msgid="1594679312161537678">"新增圖示"</string>
+ <string name="changePicture" msgid="2943329047610967714">"變更圖示"</string>
<string name="removePicture" msgid="3041230993155966350">"移除圖示"</string>
<string name="noContacts" msgid="8579310973261953559">"沒有聯絡人。"</string>
+ <string name="noMatchingContacts" msgid="4266283206853990471">"找不到符合的聯絡人。"</string>
<string name="noContactsWithPhoneNumbers" msgid="1605457050218824269">"沒有包含電話號碼的聯絡人資訊。"</string>
<string name="noFavorites" msgid="812766386743315815">"沒有我的最愛。"</string>
<string name="select_group_title" msgid="7955698611959835612">"群組"</string>
<string name="groupEmpty" msgid="6661950109828194595">"您的「<xliff:g id="GROUPNAME">%s</xliff:g>」群組是空的。"</string>
<string name="showAllGroups" msgid="5164410117611094297">"所有聯絡人"</string>
+ <string name="showFilterPhones" msgid="4184858075465653970">"僅顯示有電話號碼的聯絡人"</string>
+ <string name="showFilterPhonesDescrip" msgid="6644443248815191067">"僅顯示有電話號碼的聯絡人"</string>
+ <string name="headerContactGroups" msgid="2426134991932503843">"選擇要顯示的聯絡人"</string>
+ <plurals name="groupDescrip">
+ <item quantity="other" msgid="3507881585720628389">"<xliff:g id="COUNT">%0$d</xliff:g> 位聯絡人"</item>
+ </plurals>
+ <plurals name="groupDescripPhones">
+ <item quantity="other" msgid="3816047547470490208">"<xliff:g id="COUNT_0">%1$d</xliff:g> 位聯絡人,<xliff:g id="COUNTWITHPHONES">%2$d</xliff:g> 組電話號碼"</item>
+ </plurals>
<string name="syncAllGroups" msgid="7512169081224806890">"同步處理所有聯絡人"</string>
- <string name="groupNameMyContacts" msgid="5696566165170977126">"我的聯絡人"</string>
+ <string name="groupNameMyContacts" msgid="277995505294105439">"我的聯絡人"</string>
<string name="groupNameWithPhones" msgid="6981588604041120497">"包含電話號碼的聯絡人資訊"</string>
<string name="starredInAndroid" msgid="6495527538140213440">"在 Android 中標有星號的聯絡人"</string>
+ <string name="savingContact" msgid="4075751076741924939">"正在儲存聯絡人..."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"正在儲存顯示選項..."</string>
<string name="contactCreatedToast" msgid="8740102129968688060">"已建立聯絡人。"</string>
<string name="contactSavedToast" msgid="7152589189385441091">"聯絡人已儲存。"</string>
+ <string name="contactSavedErrorToast" msgid="9189098776225004666">"發生錯誤,無法儲存聯絡人變更。"</string>
<string name="listSeparatorCallNumber" msgid="7115321894439629408">"撥打號碼"</string>
<string name="listSeparatorCallNumber_edit" msgid="2999167270900823334">"電話號碼"</string>
- <string name="listSeparatorSendSmsMms" msgid="2480944736714739967">"傳送 SMS/MMS"</string>
+ <string name="listSeparatorSendSmsMms" msgid="5351657038532024412">"傳送簡訊"</string>
<string name="listSeparatorSendEmail" msgid="5395590830304525721">"傳送電子郵件"</string>
<string name="listSeparatorSendEmail_edit" msgid="6859593624213634454">"電子郵件地址"</string>
<string name="listSeparatorSendIm" msgid="2209260633185984105">"傳送即時訊息"</string>
@@ -110,17 +150,34 @@
<string name="listSeparatorMapAddress" msgid="7076401301758190804">"在地圖上顯示地址"</string>
<string name="listSeparatorMapAddress_edit" msgid="298711187672067985">"聯絡地址"</string>
<string name="listSeparatorOrganizations" msgid="7514083358440762504">"組織"</string>
+ <string name="listSeparatorGroups" msgid="1593940073983422450">"群組"</string>
<string name="listSeparatorOtherInformation" msgid="7844959649638482329">"其他資訊"</string>
<string name="listSeparatorOtherInformation_edit" msgid="1326921768011367750">"其他選項"</string>
<string name="listSeparatorMore_edit" msgid="858454837482243176">"更多"</string>
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one" msgid="8721111084815668845">"顯示 1 位附有電話號碼的聯絡人"</item>
+ <item quantity="other" msgid="6133262880804110289">"顯示 <xliff:g id="COUNT">%d</xliff:g> 位附有電話號碼的聯絡人"</item>
+ </plurals>
+ <string name="listTotalPhoneContactsZero" msgid="2756295259674938869">"在可顯示的聯絡人中,找不到附有電話號碼的聯絡人"</string>
+ <plurals name="listTotalAllContacts">
+ <item quantity="one" msgid="1096068709488455155">"顯示 1 位聯絡人"</item>
+ <item quantity="other" msgid="2865867557378939630">"顯示 <xliff:g id="COUNT">%d</xliff:g> 位聯絡人"</item>
+ </plurals>
+ <string name="listTotalAllContactsZero" msgid="6811347506748072822">"沒有可顯示的聯絡人"</string>
+ <plurals name="listFoundAllContacts">
+ <item quantity="one" msgid="2830107332033967280">"已找到 1 位聯絡人"</item>
+ <item quantity="other" msgid="7752927996850263152">"已找到 <xliff:g id="COUNT">%d</xliff:g> 位聯絡人"</item>
+ </plurals>
+ <string name="listFoundAllContactsZero" msgid="5554368784319460828">"找不到聯絡人"</string>
+ <string name="socialStreamIconLabel" msgid="4367712449555075376">"社交"</string>
<string name="contactsIconLabel" msgid="7666609097606552806">"聯絡人"</string>
<string name="contactsFavoritesLabel" msgid="8417039765586853670">"我的最愛"</string>
- <string name="dialerIconLabel" msgid="7228520966699542850">"撥號"</string>
+ <string name="dialerIconLabel" msgid="6500826552823403796">"電話"</string>
<string name="recentCallsIconLabel" msgid="1419116422359067949">"通話記錄"</string>
<string name="liveFolderAll" msgid="4789010460767506206">"全部聯絡人"</string>
<string name="liveFolderFavorites" msgid="3100957542927222282">"有星號標記的聯絡人"</string>
<string name="liveFolderPhone" msgid="3739376066610926780">"有電話號碼的聯絡人"</string>
- <string name="menu_sendTextMessage" msgid="455561537582270625">"傳送 SMS 訊息"</string>
+ <string name="menu_sendTextMessage" msgid="6937343460284499306">"傳送簡訊"</string>
<string name="recentCalls_callNumber" msgid="1756372533999226126">"撥電話給<xliff:g id="NAME">%s</xliff:g>"</string>
<string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"撥打電話前編輯號碼"</string>
<string name="recentCalls_addToContact" msgid="1429899535546487008">"新增至聯絡人"</string>
@@ -128,6 +185,7 @@
<string name="recentCalls_deleteAll" msgid="6352364392762163704">"清除通話記錄"</string>
<string name="recentCalls_empty" msgid="247053222448663107">"無通話記錄。"</string>
<string name="imei" msgid="3045126336951684285">"IMEI"</string>
+ <string name="meid" msgid="6210568493746275750">"MEID"</string>
<string name="voicemail" msgid="3851469869202611441">"語音留言"</string>
<string name="unknown" msgid="740067747858270469">"未知的"</string>
<string name="private_num" msgid="6374339738119166953">"私人號碼"</string>
@@ -137,10 +195,13 @@
<string name="simContacts_emptyLoading" msgid="6700035985448642408">"從 SIM 卡讀取中…"</string>
<string name="simContacts_title" msgid="27341688347689769">"SIM 卡聯絡人"</string>
<string name="contactsSyncPlug" msgid="7248276704957313698"><font fgcolor="#ffffffff">" 同步處理您的 Google 聯絡人!"</font>" "\n" 與手機同步處理後,無論您走到哪,都可存取聯絡人資訊。"</string>
- <string name="noContactsHelpText" msgid="2249195687463896364">"您沒有聯絡人。"\n\n"如要新增聯絡人,請按 ["<font fgcolor="#ffffffff"><b></b>"選單"</font>"] 並選取下列選項:"\n\n<li>"["<font fgcolor="#ffffffff"><b></b>"新增聯絡人 "</font>"]:建立新聯絡人"\n</li>" "\n<li>"["<font fgcolor="#ffffffff"><b></b>"匯入聯絡人"</font>"]:加入 SIM 卡中的聯絡人"\n</li></string>
- <string name="noContactsHelpTextWithSync" msgid="4927701496550314555">"您沒有聯絡人。"\n\n"如要新增聯絡人,請按 ["<font fgcolor="#ffffffff"><b></b>"選單"</font>"] 並選取下列選項:"\n\n" "<li>"["<font fgcolor="#ffffffff"><b></b>"編輯同步處理群組"</font>"]:加入新的或既有的 Google 帳戶聯絡人"\n</li>\n" "<li>"["<font fgcolor="#ffffffff"><b></b>"新增聯絡人"</font>"]:建立新聯絡人 "\n</li>\n" "<li>"["<font fgcolor="#ffffffff"><b></b>"匯入聯絡人"</font>"]:加入 SIM 卡中的聯絡人"\n</li></string>
+ <string name="noContactsHelpText" msgid="6788487368878712350">"您沒有任何聯絡人。"\n\n"如要新增聯絡人,請按下 ["<font fgcolor="#ffffffff">"選單"<b></b></font>"] 並輕觸:"\n" "\n<li>"["<font fgcolor="#ffffffff">"帳戶"<b></b></font>" 來新增或設定您可以同步處理手機資料的聯絡人帳戶"\n</li>" "\n<li>"["<font fgcolor="#ffffffff">"新增聯絡人"<b></b></font>"] 從頭開始建立聯絡人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"匯入/匯出"</b></font>\n</li></string>
+ <string name="noContactsHelpTextWithSync" msgid="3734101165712848179">"您沒有任何聯絡人 (如果您剛剛才新增帳戶,系統需要幾分鐘的時間才能同步聯絡人資訊)。"\n\n"如要新增聯絡人,請按下 ["<font fgcolor="#ffffffff">"選單"</font><b></b>"] 並輕觸:"\n\n"["<li><font fgcolor="#ffffffff">"帳戶"<b></b></font>"] 來新增或設定您可以同步處理手機資料的聯絡人帳戶"\n</li>" "\n<li>"["<font fgcolor="#ffffffff">"顯示選項"<b></b></font>"] 來變更聯絡人的顯示狀態"\n</li>" "\n<li>"["<font fgcolor="#ffffffff">"新增聯絡人"<b></b></font>"] 從頭開始建立聯絡人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"匯入/匯出"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpText" msgid="6553845386917463292">"您沒有任何聯絡人。"\n\n"如要新增聯絡人,請按下 ["<font fgcolor="#ffffffff">"選單"<b></b></font>"] 並輕觸:"\n" "\n<li>"["<font fgcolor="#ffffffff">"帳戶"<b></b></font>" 來新增或設定您可以同步處理手機資料的聯絡人帳戶"\n</li>" "\n<li>"["<font fgcolor="#ffffffff">"新增聯絡人"<b></b></font>"] 從頭開始建立聯絡人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"匯入/匯出"</b></font>\n</li></string>
+ <string name="noContactsNoSimHelpTextWithSync" msgid="1122296298361373488">"您沒有任何聯絡人 (如果您剛剛才新增帳戶,系統需要幾分鐘的時間才能同步聯絡人資訊)。"\n\n"如要新增聯絡人,請按下 ["<font fgcolor="#ffffffff">"選單"</font><b></b>"] 並輕觸:"\n\n"["<li><font fgcolor="#ffffffff">"帳戶"<b></b></font>"] 來新增或設定您可以同步處理手機資料的聯絡人帳戶"\n</li>" "\n<li>"["<font fgcolor="#ffffffff">"顯示選項"<b></b></font>"] 來變更聯絡人的顯示狀態"\n</li>" "\n<li>"["<font fgcolor="#ffffffff">"新增聯絡人"<b></b></font>"] 從頭開始建立聯絡人"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"匯入/匯出"</b></font>\n</li></string>
+ <string name="noFavoritesHelpText" msgid="3744655776704833277">"您沒有任何最愛。"\n\n"如要將聯絡人新增至最愛清單:"\n\n" "<li>"輕觸 [聯絡人"<b></b>"] 標籤"\n</li>" "\n<li>"輕觸要新增至最愛的聯絡人"\n</li>" "\n<li>"輕觸聯絡人名稱旁邊的星號圖示"\n</li></string>
<string name="seclectSyncGroups_title" msgid="1235432026231325655">"選取要同步處理的群組"</string>
- <string name="liveFolder_all_label" msgid="1552523730090319259">"全部聯絡人"</string>
+ <string name="liveFolder_all_label" msgid="5961411940473276616">"所有聯絡人"</string>
<string name="liveFolder_favorites_label" msgid="2674341514070517105">"星號標記"</string>
<string name="liveFolder_phones_label" msgid="1709786878793436245">"電話"</string>
<string name="dialer_useDtmfDialpad" msgid="1707548397435075040">"使用觸控音按鍵"</string>
@@ -171,8 +232,9 @@
<string name="returnCall" msgid="8171961914203617813">"回電"</string>
<string name="callDetailsDurationFormat" msgid="8157706382818184268">"<xliff:g id="MINUTES">%s</xliff:g> 分 <xliff:g id="SECONDS">%s</xliff:g> 秒"</string>
<string name="favoritesFrquentSeparator" msgid="5007070838253932139">"常用聯絡人"</string>
- <string name="add_contact_dlg_title" msgid="2789046541229846116">"新增聯絡人"</string>
+ <string name="add_contact_dlg_title" msgid="2896685845822146494">"新增聯絡人"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"要將「<xliff:g id="EMAIL">%s</xliff:g>」新增為聯絡人嗎?"</string>
+ <string name="all_tab_label" msgid="4003124364397916826">"全部"</string>
<string name="description_image_button_one" msgid="1740638037139856139">"1"</string>
<string name="description_image_button_two" msgid="5882638439003731308">"2"</string>
<string name="description_image_button_three" msgid="8709731759376015180">"3"</string>
@@ -185,43 +247,176 @@
<string name="description_image_button_star" msgid="3365919907520767866">"星號"</string>
<string name="description_image_button_zero" msgid="4133108949401820710">"0"</string>
<string name="description_image_button_pound" msgid="3039765597595889230">"磅"</string>
- <string name="no_sdcard_title" msgid="6455416795090113715">"無 SD 卡"</string>
- <string name="no_sdcard_message" msgid="7791906118138538259">"未偵測到 SD 卡"</string>
- <string name="searching_vcard_title" msgid="4158580043290687793">"正在搜尋 VCard"</string>
+ <string name="no_sdcard_title" msgid="5911758680339949273">"無 SD 卡"</string>
+ <string name="no_sdcard_message" msgid="6019391476490445358">"未偵測到 SD 卡"</string>
+ <string name="searching_vcard_title" msgid="4970508055399376813">"正在搜尋 VCard"</string>
<string name="select_import_type_title" msgid="2443742794103731022">"您要從哪裡匯入聯絡人?"</string>
- <string name="import_from_sim" msgid="3362158539070179154">"SIM 卡"</string>
- <string name="import_from_sdcard" msgid="8854793070007530689">"SD 卡"</string>
- <string name="import_all_vcard_string" msgid="2788222288962542415">"匯入所有 VCard 檔案"</string>
- <string name="import_one_vcard_string" msgid="4618119296910253689">"匯入一個 VCard 檔案"</string>
- <string name="searching_vcard_message" msgid="2467573749792455605">"正在搜尋 VCard 資料"</string>
- <string name="scanning_sdcard_failed_title" msgid="2788276113399585924">"無法掃描 SD 卡"</string>
- <string name="scanning_sdcard_failed_message" msgid="925361244069058117">"無法掃描 SD 卡"</string>
+ <string name="import_from_sim" msgid="3859272228033941659">"從 SIM 卡匯入"</string>
+ <string name="import_from_sdcard" msgid="8550360976693202816">"從 SD 卡匯入"</string>
+ <string name="export_to_sdcard" msgid="2597105442616166277">"匯出至 SD 卡"</string>
+ <string name="import_one_vcard_string" msgid="9059163467020328433">"匯入一個 vCard 檔案"</string>
+ <string name="import_multiple_vcard_string" msgid="3810226492811062392">"匯入多個 vCard 檔案"</string>
+ <string name="import_all_vcard_string" msgid="5518136113853448474">"匯入所有 vCard 檔案"</string>
+ <string name="searching_vcard_message" msgid="6917522333561434546">"在 SD 卡上搜尋 VCard 資料"</string>
+ <string name="scanning_sdcard_failed_title" msgid="3506782007953167180">"無法掃描 SD 卡"</string>
+ <string name="scanning_sdcard_failed_message" msgid="3761992500690182922">"無法掃描 SD 卡 (原因:「<xliff:g id="FAIL_REASON">%s</xliff:g>」)"</string>
<string name="fail_reason_io_error" msgid="5922864781066136340">"I/O 錯誤"</string>
- <string name="fail_reason_vcard_parse_error" msgid="2129476089250836277">"無法剖析 VCard"</string>
- <string name="fail_reason_no_vcard_file" msgid="1489638537002538332">"SD 卡上沒有 VCard 檔案"</string>
- <string name="fail_reason_no_vcard_entry" msgid="3808734131680935043">"您所選的檔案沒有有效的 VCard 項目"</string>
- <string name="select_vcard_title" msgid="4615933643517710543">"選取 VCard 檔案"</string>
- <string name="select_vcard_message" msgid="7028772212789057858">"請選取要匯入的 VCard 檔案"</string>
- <string name="reading_vcard_title" msgid="430154704397375160">"讀取 VCard"</string>
- <string name="reading_vcard_message" msgid="7470486051482460267">"正在讀取 VCard 檔案"</string>
- <string name="importing_vcard_message" msgid="2466665710812588738">"正在匯入 VCard 資料"</string>
- <string name="reading_vcard_failed_title" msgid="5042366466147724748">"無法讀取 VCard 資料"</string>
- <string name="reading_vcard_failed_message" msgid="780588344175743735">"無法讀取 VCard 資料"\n"失敗原因:「<xliff:g id="FAIL_REASON">%s</xliff:g>」"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"因未預期原因,無法剖析 VCard"</string>
+ <string name="fail_reason_vcard_not_supported_error" msgid="655208100451286027">"VCard 格式正確,但目前的實作系統不支援此格式,因此無法剖析"</string>
+ <string name="fail_reason_no_vcard_file" msgid="6376516175882881595">"SD 卡上沒有 vCard 檔案"</string>
+ <string name="fail_reason_no_vcard_entry" msgid="4733290752474073143">"所選的檔案中沒有有效的 VCard 項目"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"無法匯入一或多個檔案 (%s)。"</string>
+ <string name="fail_reason_unknown" msgid="999034019513096768">"未知的錯誤"</string>
+ <string name="select_vcard_title" msgid="3968948173786172468">"選取 VCard 檔案"</string>
+ <string name="select_vcard_message" msgid="221189184212818304">"請選取要匯入的 VCard 檔案"</string>
+ <string name="progress_shower_message" msgid="5636525578293752526">"<xliff:g id="ACTION">%s</xliff:g>"\n"<xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_title" msgid="4723433501579653199">"正在讀取 VCard"</string>
+ <string name="reading_vcard_message" msgid="6381368920030748743">"正在讀取 VCard 檔案"</string>
+ <string name="importing_vcard_message" msgid="4046655384673753503">"正在匯入 VCard 資料"</string>
+ <string name="reading_vcard_failed_title" msgid="4923008144735294994">"無法讀取 VCard 資料"</string>
+ <string name="reading_vcard_failed_message" msgid="5684089173948287107">"無法讀取 VCard。"\n"失敗原因:「<xliff:g id="FAIL_REASON">%s</xliff:g>」"</string>
<string name="reading_vcard_contacts" msgid="3066834102042012868">"第 <xliff:g id="CURRENT_NUMBER">%s</xliff:g> 位聯絡人,共 <xliff:g id="TOTAL_NUMBER">%s</xliff:g> 位"</string>
<string name="reading_vcard_files" msgid="34180143726972661">"第 <xliff:g id="CURRENT_NUMBER">%s</xliff:g> 個檔案,共 <xliff:g id="TOTAL_NUMBER">%s</xliff:g> 個"</string>
+ <string name="export_all_contacts" msgid="2873892623335194071">"所有聯絡人"</string>
+ <string name="export_phone_local_only" msgid="3380497955409896761">"儲存在本機的聯絡人"</string>
<string name="export_contact_list" msgid="3165097742175874384">"匯出聯絡人"</string>
- <string name="confirm_export_title" msgid="1693047909433122854">"確認匯出"</string>
- <string name="confirm_export_message" msgid="63482084706768079">"可以將聯絡人清單匯出至「<xliff:g id="VCARD_FILENAME">%s</xliff:g>」嗎?"</string>
- <string name="exporting_contact_failed_title" msgid="1455264422455075858">"無法匯出聯絡人資料"</string>
- <string name="exporting_contact_failed_message" msgid="1426451081541603512">"無法匯出聯絡人資料"\n"失敗原因:「<xliff:g id="FAIL_REASON">%s</xliff:g>」"</string>
- <string name="fail_reason_too_many_vcard" msgid="5416992255233341607">"SD 卡上儲存的 VCard 資料過多"</string>
- <string name="fail_reason_too_long_filename" msgid="7105223965196949065">"您輸入的檔案名稱過長 (「<xliff:g id="FILENAME">%s</xliff:g>」)"</string>
+ <string name="confirm_export_title" msgid="7648747763127442983">"確認匯出"</string>
+ <string name="confirm_export_message" msgid="3875683519257829750">"確定要將聯絡人清單匯出至「<xliff:g id="VCARD_FILENAME">%s</xliff:g>」嗎?"</string>
+ <string name="exporting_contact_failed_title" msgid="585823094820602526">"無法匯出聯絡人資料"</string>
+ <string name="exporting_contact_failed_message" msgid="4151348002470298092">"匯出聯絡人資料失敗。"\n"失敗原因:「<xliff:g id="FAIL_REASON">%s</xliff:g>」"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"沒有可匯出的聯絡人"</string>
+ <string name="fail_reason_too_many_vcard" msgid="7084146295639672658">"SD 卡中的 VCard 檔案過多"</string>
+ <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"要求的檔案名稱過長 (「<xliff:g id="FILENAME">%s</xliff:g>」)"</string>
<string name="fail_reason_cannot_open_destination_dir" msgid="1739293936432987758">"無法開啟或建立目標目錄「<xliff:g id="DIR_NAME">%s</xliff:g>」"</string>
<string name="exporting_contact_list_title" msgid="9072240631534457415">"正在匯出聯絡人資料"</string>
<string name="exporting_contact_list_message" msgid="5640326540405486055">"正在將聯絡人資料匯出至「<xliff:g id="FILE_NAME">%s</xliff:g>」"</string>
<string name="fail_reason_could_not_initialize_exporter" msgid="4943708332700987376">"無法初始化匯出程式:「<xliff:g id="EXACT_REASON">%s</xliff:g>」"</string>
<string name="fail_reason_error_occurred_during_export" msgid="2151165129433831202">"匯出時發生錯誤:「<xliff:g id="EXACT_REASON">%s</xliff:g>」"</string>
+ <string name="composer_failed_to_get_database_infomation" msgid="3723109558155169053">"無法取得資料庫資訊"</string>
+ <string name="composer_has_no_exportable_contact" msgid="2239503301380653777">"沒有可匯出的聯絡人,您可能選擇了不可匯出的資料。"</string>
+ <string name="composer_not_initialized" msgid="8041534450748388843">"VCard 編輯器並未正確初始化"</string>
<string name="fail_reason_could_not_open_file" msgid="4013520943128739511">"無法開啟「<xliff:g id="FILE_NAME">%s</xliff:g>」:<xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
<string name="exporting_contact_list_progress" msgid="560522409559101193">"第 <xliff:g id="CURRENT_NUMBER">%s</xliff:g> 位聯絡人,共 <xliff:g id="TOTAL_NUMBER">%s</xliff:g> 位"</string>
<string name="search_settings_description" msgid="2675223022992445813">"您的聯絡人姓名"</string>
+ <string name="add_2sec_pause" msgid="9214012315201040129">"新增 2 秒暫停功能"</string>
+ <string name="add_wait" msgid="3360818652790319634">"新增插播功能"</string>
+ <string name="dial_button_label" msgid="7637725632722605863">"撥號"</string>
+ <string name="call_disambig_title" msgid="1911302597959335178">"去電使用"</string>
+ <string name="sms_disambig_title" msgid="4675399294513152364">"簡訊使用:"</string>
+ <string name="make_primary" msgid="5829291915305113983">"記住這個選擇"</string>
+ <string name="quickcontact_missing_app" msgid="4600366393134289038">"找不到可以處理這個動作的應用程式"</string>
+ <string name="quickcontact_remember_choice" msgid="5964536411579749424">"記住這個選擇"</string>
+ <string name="quickcontact_missing_name" msgid="5590266114306996632">"不明"</string>
+ <string name="menu_accounts" msgid="8499114602017077970">"帳戶"</string>
+ <string name="menu_import_export" msgid="3765725645491577190">"匯入/匯出"</string>
+ <string name="dialog_import_export" msgid="4771877268244096596">"匯入/匯出聯絡人"</string>
+ <string name="menu_share" msgid="943789700636542260">"分享"</string>
+ <string name="share_via" msgid="563121028023030093">"使用下列應用程式分享聯絡人資訊:"</string>
+ <string name="share_error" msgid="4374508848981697170">"無法分享此聯絡人。"</string>
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"姓名"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"暱稱"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"機構"</string>
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"網站"</string>
+ <string name="eventLabelsGroup" msgid="8069912895912714412">"活動"</string>
+ <string name="type_short_home" msgid="7770424864090605384">"住家"</string>
+ <string name="type_short_mobile" msgid="1655473281466676216">"行動"</string>
+ <string name="type_short_work" msgid="4925330752504537861">"工作"</string>
+ <string name="type_short_pager" msgid="2613818970827594238">"呼叫器"</string>
+ <string name="type_short_other" msgid="5669407180177236769">"其他"</string>
+ <string name="edit_read_only" msgid="8158629550655830981">"此聯絡人為唯讀"</string>
+ <string name="edit_secondary_collapse" msgid="5371618426594477103">"更多"</string>
+ <string name="dialog_primary_name" msgid="5521591005692614833">"主要名稱"</string>
+ <string name="dialog_new_contact_account" msgid="9044704073286262197">"在帳戶下建立聯絡人"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"移除同步處理群組"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"新增同步處理群組"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"更多群組..."</string>
+ <string name="display_ungrouped" msgid="4602580795576261158">"所有其他聯絡人"</string>
+ <string name="display_all_contacts" msgid="6846131371214707956">"所有聯絡人"</string>
+ <string name="display_warn_remove_ungrouped" msgid="2314043155909167610">"如果從同步處理群組中移除「<xliff:g id="GROUP">%s</xliff:g>」群組,系統也會從同步處理群組中移除所有未分組的聯絡人。"</string>
+ <string name="account_phone" msgid="4025734638492419713">"僅儲存於手機 (不會同步處理)"</string>
+ <string name="label_email_display_name" msgid="5537802602754309600">"顯示名稱"</string>
+ <string name="call_custom" msgid="7756571794763171802">"去電<xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"去電住家電話"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"去電行動裝置"</string>
+ <string name="call_work" msgid="5328785911463744028">"去電公司電話"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"去電公司傳真"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"去電住家傳真"</string>
+ <string name="call_pager" msgid="9003902812293983281">"去電呼叫器"</string>
+ <string name="call_other" msgid="5605584621798108205">"去電其他電話"</string>
+ <string name="call_callback" msgid="1910165691349426858">"去電回撥號碼"</string>
+ <string name="call_car" msgid="3280537320306436445">"去電汽車電話"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"去電公司代表號"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"去電 ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"去電代表號"</string>
+ <string name="call_other_fax" msgid="7777261153532968503">"去電其他傳真電話"</string>
+ <string name="call_radio" msgid="8296755876398357063">"去電無線電"</string>
+ <string name="call_telex" msgid="2223170774548648114">"去電 Telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"去電 TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"去電公司行動電話"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"去電公司呼叫器"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"去電<xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"去電 MMS"</string>
+ <string name="sms_custom" msgid="5932736853732191825">"傳送簡訊至<xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"傳送簡訊至住家電話"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"傳送簡訊至行動裝置"</string>
+ <string name="sms_work" msgid="2269624156655267740">"傳送簡訊至公司電話"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"傳送簡訊至公司傳真"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"傳送簡訊至住家傳真"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"傳送簡訊至呼叫器"</string>
+ <string name="sms_other" msgid="5131921487474531617">"傳送簡訊至其他裝置"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"傳送簡訊至回撥號碼"</string>
+ <string name="sms_car" msgid="7444227058437359641">"傳送簡訊至汽車電話"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"傳送簡訊至公司代表號"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"傳送簡訊至 ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"傳送簡訊至代表號"</string>
+ <string name="sms_other_fax" msgid="3930666870074006114">"傳送簡訊至其他傳真電話"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"傳送簡訊至無線電"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"傳送簡訊至 Telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"傳送簡訊至 TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"傳送簡訊至公司行動電話"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"傳送簡訊至公司呼叫器"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"傳送簡訊至<xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"傳送 MMS 簡訊"</string>
+ <string name="email_home" msgid="8573740658148184279">"傳送電子郵件至住家電子郵件地址"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"傳送電子郵件至行動裝置"</string>
+ <string name="email_work" msgid="2807430017302722689">"傳送電子郵件至公司電子郵件地址"</string>
+ <string name="email_other" msgid="8093933498541795832">"傳送電子郵件至其他電子郵件地址"</string>
+ <string name="email_custom" msgid="7548003991586214105">"傳送電子郵件至<xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"傳送電子郵件"</string>
+ <string name="map_home" msgid="1243547733423343982">"檢視住家地址"</string>
+ <string name="map_work" msgid="1360474076921878088">"檢視公司地址"</string>
+ <string name="map_other" msgid="5560707927535653892">"檢視其他地址"</string>
+ <string name="map_custom" msgid="6184363799976265281">"檢視<xliff:g id="CUSTOM">%s</xliff:g>地址"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"使用 AIM 進行即時通訊"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"使用 Windows Live 進行即時通訊"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"使用 Yahoo 進行即時通訊"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"使用 Skype 進行即時通訊"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"使用 QQ 進行即時通訊"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"使用 Google Talk 進行即時通訊"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"使用 ICQ 進行即時通訊"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"使用 Jabber 進行即時通訊"</string>
+ <string name="chat" msgid="9025361898797412245">"即時通訊"</string>
+ <string name="postal_street" msgid="8133143961580058972">"街道"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"郵政信箱"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"鄰"</string>
+ <string name="postal_city" msgid="6597491300084895548">"鄉/鎮/市/區"</string>
+ <string name="postal_region" msgid="6045263193478437672">"州/省"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"郵遞區號"</string>
+ <string name="postal_country" msgid="7638264508416368690">"國家/地區"</string>
+ <string name="name_given" msgid="1687286314106019813">"名字"</string>
+ <string name="name_family" msgid="3416695586119999058">"姓氏"</string>
+ <string name="name_prefix" msgid="59756378548779822">"姓名前稱銜"</string>
+ <string name="name_middle" msgid="8467433655992690326">"中間名"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"姓名後稱銜"</string>
+ <string name="name_phonetic_given" msgid="6853570431394449191">"名字 (拼音)"</string>
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"中間名 (拼音)"</string>
+ <string name="name_phonetic_family" msgid="462095502140180305">"姓氏 (拼音)"</string>
+ <string name="split_label" msgid="8262112659919449087">"分割"</string>
+ <string name="split_explanation" msgid="1824739956426973592">"使用這項資料新建聯絡人。"</string>
+ <string name="account_name_format" msgid="4421123930035299208">"<xliff:g id="SOURCE">%1$s</xliff:g> 帳戶:<xliff:g id="ACCOUNT">%2$s</xliff:g>"</string>
+ <string name="account_type_format" msgid="718948015590343010">"<xliff:g id="SOURCE">%1$s</xliff:g> 聯絡人"</string>
+ <string name="from_account_format" msgid="687567483928582084">"來自 <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="use_photo_as_primary" msgid="8807110122951157246">"使用此相片"</string>
+ <string name="contact_read_only" msgid="1203216914575723978">"無法在此裝置編輯 <xliff:g id="SOURCE">%1$s</xliff:g> 的聯絡人資訊"</string>
+ <string name="no_contact_details" msgid="6754415338321837001">"沒有此聯絡人的其他資訊"</string>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
new file mode 100644
index 0000000..661634b
--- /dev/null
+++ b/res/values/attrs.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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>
+ <!-- Maps a contact kind or mime-type to a RemoteViews XML formatter -->
+ <declare-styleable name="Mapping">
+ <!-- Mime-type handled by this mapping -->
+ <attr name="mimeType" format="string" />
+ <!-- RemoteViews XML that should be used to format this data -->
+ <attr name="remoteViews" format="reference" />
+ <!-- Icon that should be used to represent this data -->
+ <attr name="icon" format="reference" />
+ <!-- Column in data table to summarize this data -->
+ <attr name="summaryColumn" format="string" />
+ <!-- Column in data table to show details of this data -->
+ <attr name="detailColumn" format="string" />
+ </declare-styleable>
+
+ <declare-styleable name="EdgeTriggerView">
+ <attr name="edgeWidth" format="dimension" />
+ <attr name="listenEdges">
+ <flag name="left" value="0x01" />
+ <flag name="right" value="0x02" />
+ </attr>
+ </declare-styleable>
+
+</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index fb4019d..69ab865 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -4,9 +4,9 @@
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.
@@ -17,4 +17,9 @@
<resources>
<color name="textColorIconOverlay">#fff</color>
<color name="textColorIconOverlayShadow">#000</color>
+ <color name="sect_secondary">#4fff</color>
+ <color name="quickcontact_disambig">#f2f2f2</color>
+ <color name="quickcontact_disambig_divider">#afafaf</color>
+
+ <color name="edit_divider">#ff666666</color>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index d7a3be4..93d19e9 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -19,7 +19,7 @@
<resources>
<!-- Flag indicating whether Contacts app is allowed to import contacts from SDCard -->
- <bool name="config_allow_import_from_sdcard">false</bool>
+ <bool name="config_allow_import_from_sdcard">true</bool>
<!-- If true, all vcard files are imported from SDCard without asking a user.
If not, dialog shows to let the user to select whether all vcard files are imported or not.
If the user selects "not", then the application ask the user to select a file.-->
@@ -29,27 +29,37 @@
skipped and the importer asks the user to choose one vcard file.
If config_import_all_vcard_from_sdcard_automatically is set true, this configuration
is ignored. -->
- <bool name="config_allow_users_select_all_vcard_import">false</bool>
+ <bool name="config_allow_users_select_all_vcard_import">true</bool>
<!-- Flag indicating whether Contacts app is allowed to export contacts to SDCard -->
- <bool name="config_allow_export_to_sdcard">false</bool>
+ <bool name="config_allow_export_to_sdcard">true</bool>
- <!-- The type of VCard for export. Without specifying this, generic VCard will be emitted.
- If you want to let the app emit VCard specific to some vendor (like DoCoMo),
- please specify the type.-->
- <string name="config_export_vcard_type"></string>
+ <!-- If true, enable vibration (haptic feedback) for dialer key presses.
+ The pattern is set on a per-platform basis using config_virtualKeyVibePattern.
+ TODO: If enough users are annoyed by this, we might eventually
+ need to make it a user preference rather than a per-platform
+ resource. -->
+ <bool name="config_enable_dialer_key_vibration">true</bool>
+
+ <!-- The type of vcard for improt. If the vcard importer cannot guess the exact type
+ of a vCard type, the improter uses this type. -->
+ <string name="config_import_vcard_type" translatable="false">default</string>
+
+ <!-- The type of VCard for export. If you want to let the app emit vCard which is
+ specific to some vendor (like DoCoMo), specify this type (e.g. "docomo") -->
+ <string name="config_export_vcard_type" translatable="false">default</string>
<!-- Directory in which exported VCard file is stored -->
- <string name="config_export_dir">/sdcard</string>
+ <string name="config_export_dir" translatable="false">/sdcard</string>
<!-- Prefix of exported VCard file -->
- <string name="config_export_file_prefix"></string>
+ <string name="config_export_file_prefix" translatable="false"></string>
<!-- Suffix of exported VCard file. Attached before an extension -->
- <string name="config_export_file_suffix"></string>
+ <string name="config_export_file_suffix" translatable="false"></string>
<!-- Extension for exported VCard files -->
- <string name="config_export_file_extension">vcf</string>
+ <string name="config_export_file_extension" translatable="false">vcf</string>
<!-- Minimum number of exported VCard file index -->
<integer name="config_export_file_min_index">1</integer>
@@ -61,5 +71,12 @@
config_export_extension. e.g. If "aaa" is added to here and 00001.vcf and 00002.aaa
exist in a target directory, 00003.vcf becomes a next file name candidate.
Without this configuration, 00002.vcf becomes the candidate.-->
- <string name="config_export_extensions_to_consider"></string>
+ <string name="config_export_extensions_to_consider" translatable="false"></string>
+
+ <!-- If true, show an onscreen "Dial" button in the dialer.
+ In practice this is used on all platforms even the ones with hard SEND/END
+ keys, but for maximum flexibility it's controlled by a flag here
+ (which can be overridden on a per-product basis.) -->
+ <bool name="config_show_onscreen_dial_button">true</bool>
+
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
new file mode 100644
index 0000000..a82f5a9
--- /dev/null
+++ b/res/values/dimens.xml
@@ -0,0 +1,27 @@
+<?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>
+ <dimen name="quickcontact_shadow_horiz">30dip</dimen>
+ <dimen name="quickcontact_shadow_vert">37dip</dimen>
+ <dimen name="quickcontact_shadow_touch">20dip</dimen>
+
+ <dimen name="edit_photo_size">76dip</dimen>
+
+ <!-- The height of the ScrollingTabWidget -->
+ <dimen name="tab_height">40dip</dimen>
+ <dimen name="account_name_height">25dip</dimen>
+</resources>
diff --git a/res/values/ids.xml b/res/values/ids.xml
index fb1fe41..5e287ad 100644
--- a/res/values/ids.xml
+++ b/res/values/ids.xml
@@ -4,9 +4,9 @@
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.
@@ -17,4 +17,39 @@
<resources>
<!-- The EditText for entries in the EditContactActivity -->
<item type="id" name="data" />
+
+ <item type="id" name="header_phones" />
+
+ <item type="id" name="dialog_delete" />
+ <item type="id" name="dialog_photo" />
+ <item type="id" name="dialog_name" />
+ <item type="id" name="dialog_label" />
+ <item type="id" name="dialog_label_custom" />
+
+ <item type="id" name="dialog_sync_add" />
+
+ <item type="id" name="dialog_import_export" />
+
+ <!-- For ImportVCardActivity -->
+ <item type="id" name="dialog_searching_vcard" />
+ <item type="id" name="dialog_sdcard_not_found" />
+ <item type="id" name="dialog_vcard_not_found" />
+ <item type="id" name="dialog_select_import_type" />
+ <item type="id" name="dialog_select_one_vcard" />
+ <item type="id" name="dialog_select_multiple_vcard" />
+ <item type="id" name="dialog_reading_vcard" />
+ <item type="id" name="dialog_io_exception" />
+ <item type="id" name="dialog_error_with_message" />
+
+ <!-- For ContactsListActivity -->
+ <item type="id" name="dialog_delete_contact_confirmation" />
+ <item type="id" name="dialog_readonly_contact_hide_confirmation" />
+ <item type="id" name="dialog_multiple_contact_delete_confirmation" />
+ <item type="id" name="dialog_readonly_contact_delete_confirmation" />
+
+ <!-- For ExportVCard -->
+ <item type="id" name="dialog_export_confirmation" />
+ <item type="id" name="dialog_exporting_vcard" />
+ <item type="id" name="dialog_fail_to_export_with_reason" />
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c6add99..e37c118 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4,9 +4,9 @@
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.
@@ -21,7 +21,7 @@
<!-- Title for the activity that dials the phone. This is the name
used in the Launcher icon. -->
- <string name="launcherDialer">Dialer</string>
+ <string name="launcherDialer">Phone</string>
<!-- Name of activity that allows users to create shortcuts on the home screen to a contact.
This shows up in a list of things like bookmark, folder, music playlist, etc -->
@@ -29,21 +29,21 @@
<!-- Name of activity that allows users to create shortcuts on the home screen to dial a contact.
This shows up in a list of things like bookmark, folder, music playlist, etc -->
- <string name="shortcutDialContact">Direct Dial</string>
+ <string name="shortcutDialContact">Direct dial</string>
<!-- Name of activity that allows users to create shortcuts on the home screen to message (SMS) a contact.
This shows up in a list of things like bookmark, folder, music playlist, etc -->
- <string name="shortcutMessageContact">Direct Message</string>
+ <string name="shortcutMessageContact">Direct message</string>
<!-- Activity title when the user is selecting a contact for a shortcut. -->
<string name="shortcutActivityTitle">Choose a contact shortcut</string>
-
+
<!-- Activity title when the user is selecting a contact for a direct dial shortcut. -->
<string name="callShortcutActivityTitle">Choose a number to call</string>
-
+
<!-- Activity title when the user is selecting a contact for a direct message shortcut. -->
<string name="messageShortcutActivityTitle">Choose a number to message</string>
-
+
<!-- Title for the activity that shows only starred contacts -->
<string name="starredList">Starred</string>
@@ -56,11 +56,11 @@
<!-- The title bar when viewing the contact details activity -->
<string name="viewContactTitle">Contact details</string>
-
+
<!-- The description presented to the user in the Intent choose when there are multiple activities that allow
viewing a contact. This string represents the built in way to view the contact. -->
<string name="viewContactDesription">View contact</string>
-
+
<!-- The description presented to the user in the Intent choose when there are multiple activities that allow
editing a contact. This string represents the built in way to edit the contact. -->
<string name="editContactDescription">Edit contact</string>
@@ -100,10 +100,10 @@
<string name="menu_deleteContact">Delete contact</string>
<!-- Menu item used to call a specific contact when viewing the details of that contact. -->
- <string name="menu_call">Call</string>
+ <string name="menu_call">Call contact</string>
<!-- Menu item used to send an SMS or MMS message to a specific phone number or a contacts default phone number -->
- <string name="menu_sendSMS">Send SMS/MMS</string>
+ <string name="menu_sendSMS">Text contact</string>
<!-- Menu item used to send an email message to a specific email address -->
<string name="menu_sendEmail">Send email</string>
@@ -115,10 +115,74 @@
try to call a contact without specifying a specific number. -->
<string name="menu_makeDefaultNumber">Make default number</string>
+ <!-- Menu item that makes an email address the default for a contact. The default email used
+ when you try to email a contact without specifying a specific address. -->
+ <string name="menu_makeDefaultEmail">Make default email</string>
+
+ <!-- Menu item that splits an item from the contact detail into a separate aggregate -->
+ <string name="menu_splitAggregate">Separate</string>
+
+ <!-- Dialog title for the list of constituent contacts in the split aggregate dialog. -->
+ <string name="splitAggregate_title">Split contact</string>
+
+ <!-- Toast shown after a contact has been split from an aggregate by a user action -->
+ <string name="contactsSplitMessage">Contacts separated</string>
+
+ <!-- Title of the confirmation dialog for separating contacts into multiple instances -->
+ <string name="splitConfirmation_title">Separate Contact</string>
+
+ <!-- Confirmation dialog for separating contacts into multiple instances -->
+ <string name="splitConfirmation">Are you sure you want to separate this single contact
+ into multiple contacts: one for each set of contact information that was joined into it?
+ </string>
+
+ <!-- Menu item that joins an aggregate with another aggregate -->
+ <string name="menu_joinAggregate">Join</string>
+
+ <!-- Menu item to toggle the tabs that show where the contact data comes from. -->
+ <string name="menu_showSources">Show sources</string>
+ <string name="menu_hideSources">Hide sources</string>
+
+ <!-- Activity title for the Join Contact list -->
+ <string name="titleJoinAggregate">Join contact</string>
+
+ <!-- Heading of the Join Contact screen -->
+ <string name="titleJoinContactDataWith">Join contacts</string>
+
+ <!-- Info blurb on the Join Contact screen -->
+ <string name="blurbJoinContactDataWith">Select the contact you want to join with <xliff:g id="name">%s</xliff:g>.</string>
+
+ <!-- An item in the Join Contact activity that opens up the full contact A-Z list -->
+ <string name="showAllContactsJoinItem">Show all contacts</string>
+
+ <!-- List separator for the Join Contact list: Suggestions -->
+ <string name="separatorJoinAggregateSuggestions">Suggested contacts</string>
+
+ <!-- List separator for the Join Contact list: A-Z -->
+ <string name="separatorJoinAggregateAll">All contacts</string>
+
+ <!-- Toast shown after two contacts have been joined by a user action -->
+ <string name="contactsJoinedMessage">Contacts joined</string>
+
+ <!-- Menu item that opens the Options activity for a given contact -->
+ <string name="menu_contactOptions">Options</string>
+
+ <!-- Title for the Options activity for a given contact -->
+ <string name="contactOptionsTitle">Options</string>
+
<!-- Confirmation dialog title after users selects to delete a contact. -->
<string name="deleteConfirmation_title">Delete</string>
- <!-- Confirmation dialog contents after users selects to delete a contact. -->
+ <!-- Warning dialog contents after users selects to delete a ReadOnly contact. -->
+ <string name="readOnlyContactWarning">You cannot delete contacts from read-only accounts, but you can hide them in your contacts lists.</string>
+
+ <!-- Warning dialog contents after users selects to delete a contact with ReadOnly and Writable sources. -->
+ <string name="readOnlyContactDeleteConfirmation">This contact contains information from multiple accounts. Information from read-only accounts will be hidden in your contacts lists, not deleted.</string>
+
+ <!-- Warning dialog contents after users selects to delete a contact with multiple Writable sources. -->
+ <string name="multipleContactDeleteConfirmation">Deleting this contact will delete information from multiple accounts.</string>
+
+ <!-- Confirmation dialog contents after users selects to delete a Writable contact. -->
<string name="deleteConfirmation">This contact will be deleted.</string>
<!-- Menu item to indicate you are done editing a contact and want to save the changes you've made -->
@@ -145,6 +209,15 @@
<!-- The label describing the custom ringtone for a contact -->
<string name="label_ringtone">Ringtone</string>
+ <!-- The label for a list of all the groups that the contact is associated with -->
+ <string name="label_groups">Groups</string>
+
+ <!-- Provides a delimeter in a list of groups. For example, "g1, g2" has ", g2" generated using this string -->
+ <string name="group_list">, <xliff:g id="groupName">%s</xliff:g></string>
+
+ <!-- Menu item used to send user to the edit contact screen -->
+ <string name="menu_viewGroup">Edit groups</string>
+
<!-- Hint text for the contact name when editing -->
<string name="ghostData_name">First and Last</string>
@@ -172,6 +245,9 @@
<!-- Hint text for the postal address field when editing -->
<string name="ghostData_postal">Postal address</string>
+ <!-- Hint text for the group field when editing -->
+ <string name="ghostData_group">Display group</string>
+
<!-- Message displayed in a toast when you try to view the details of a contact that
for some reason doesn't exist anymore. -->
<string name="invalidContactMessage">The contact does not exist.</string>
@@ -222,11 +298,14 @@
<string name="customLabelPickerTitle">Custom label name</string>
<!-- The menu item to open the list of groups to display -->
- <string name="menu_displayGroup">Display group</string>
+ <string name="menu_displayGroup">Display options</string>
+
+ <!-- Title of activity that lets user pick which contact groups to display -->
+ <string name="displayGroups">Display options</string>
<!-- The menu item that leads to the settings for contact syncing -->
<string name="syncGroupPreference">Edit sync groups</string>
-
+
<!-- The menu item that launches the SIM card import activity -->
<string name="importFromSim">Import contacts</string>
@@ -242,12 +321,18 @@
<!-- The button/menu item that allows you to add a picture to a contact -->
<string name="addPicture">Add icon</string>
+ <!-- The button/menu item that allows you to change an existing contact picture -->
+ <string name="changePicture">Change icon</string>
+
<!-- The menu item that allows you to remove a picture from a contact -->
<string name="removePicture">Remove icon</string>
<!-- The text displayed when the contacts list is empty while displaying all contacts -->
<string name="noContacts">No contacts.</string>
+ <!-- The text displayed when the contacts list is empty while displaying results after searching contacts -->
+ <string name="noMatchingContacts">No matching contacts found.</string>
+
<!-- The text displayed when the contacts list is empty while displaying only contacts that have phone numbers -->
<string name="noContactsWithPhoneNumbers">No contacts with phone numbers.</string>
@@ -257,31 +342,59 @@
<!-- Title for group selection dialog. The dialog contains a list of contact groups that the
user can pick from, indicating they only want to see the contacts in that group. -->
<string name="select_group_title">Groups</string>
-
+
<!-- The text displayed when the contacts list is empty while displaying a single group of contacts -->
<string name="groupEmpty">Your \"<xliff:g id="groupName">%s</xliff:g>\" group is empty.</string>
<!-- The description of all groups when asking the user what they want to display -->
<string name="showAllGroups">All contacts</string>
+ <!-- The title of the filter to only show contacts with phone numbers -->
+ <string name="showFilterPhones">Only contacts with phones</string>
+
+ <!-- The description of the filter to only show contacts with phone numbers -->
+ <string name="showFilterPhonesDescrip">Only display contacts that have phone numbers</string>
+
+ <!-- The header over the list of all contacts groups -->
+ <string name="headerContactGroups">Choose contacts to display</string>
+
+ <!-- The description of a group with the total number of contacts -->
+ <plurals name="groupDescrip">
+ <item quantity="other"><xliff:g id="count">%0$d</xliff:g> contacts</item>
+ </plurals>
+
+ <!-- The description of a group with the total number of contacts, and the total number of contacts with phone numbers -->
+ <plurals name="groupDescripPhones">
+ <item quantity="other"><xliff:g id="count">%1$d</xliff:g> contacts, <xliff:g id="countWithPhones">%2$d</xliff:g> with phones</item>
+ </plurals>
+
<!-- The setting to sync all contacts from the server -->
<string name="syncAllGroups">Sync all contacts</string>
<!-- The name of the system "My Contacts" group. This should be kept in sync with the web UI -->
- <string name="groupNameMyContacts">My Contacts</string>
-
+ <string name="groupNameMyContacts">My contacts</string>
+
<!-- The group type that displays only contacts with phone numbers -->
<string name="groupNameWithPhones">Contacts with phone numbers</string>
-
+
<!-- The group type that displays "Starred in Android" contacts -->
<string name="starredInAndroid">Starred in Android</string>
-
+
+ <!-- Displayed in a spinner dialog after the user creates a contact and it's being saved to the database -->
+ <string name="savingContact">Saving contact\u2026</string>
+
+ <!-- Displayed in a spinner dialog as user changes to display options are saved -->
+ <string name="savingDisplayGroups">Saving display options\u2026</string>
+
<!-- Toast displayed when a contact is created -->
<string name="contactCreatedToast">Contact created.</string>
-
+
<!-- Toast displayed when a contact is saved -->
<string name="contactSavedToast">Contact saved.</string>
+ <!-- Toast displayed when saving a contact failed -->
+ <string name="contactSavedErrorToast">Error, unable to save contact changes.</string>
+
<!-- Separator in the contact details list describing that the items below it will place a call when clicked -->
<string name="listSeparatorCallNumber">Dial number</string>
@@ -289,7 +402,7 @@
<string name="listSeparatorCallNumber_edit">Phone numbers</string>
<!-- Separator in the contact details list describing that the items below it will send an SMS/MMS to a phone number -->
- <string name="listSeparatorSendSmsMms">Send SMS/MMS</string>
+ <string name="listSeparatorSendSmsMms">Send text</string>
<!-- Separator in the contact details list describing that the items below it will send an email -->
<string name="listSeparatorSendEmail">Send email</string>
@@ -312,6 +425,9 @@
<!-- Separator in the contact details list describing that the items below are non-actionable organization information -->
<string name="listSeparatorOrganizations">Organizations</string>
+ <!-- Separator in the contact details list describing that the items below are non-actionable group information -->
+ <string name="listSeparatorGroups">Groups</string>
+
<!-- Separator in the contact details list describing that the items below are random other non-actionable information about a contact -->
<string name="listSeparatorOtherInformation">Other information</string>
@@ -321,6 +437,36 @@
<!-- Section header in the Edit Contacts screen for the "Add more items" button -->
<string name="listSeparatorMore_edit">More</string>
+ <!-- Displayed at the top of the contacts showing the total number of contacts visible when "Only contacts with phones" is selected -->
+ <plurals name="listTotalPhoneContacts">
+ <item quantity="one">Displaying 1 contact with phone number</item>
+ <item quantity="other">Displaying <xliff:g id="count">%d</xliff:g> contacts with phone numbers</item>
+ </plurals>
+
+ <!-- Displayed at the top of the contacts showing the zero as total number of contacts visible when "Only contacts with phones" is selected -->
+ <string name="listTotalPhoneContactsZero">No visible contacts with phone numbers</string>
+
+ <!-- Displayed at the top of the contacts showing the total number of contacts visible when "Only contacts with phones" not selected -->
+ <plurals name="listTotalAllContacts">
+ <item quantity="one">Displaying 1 contact</item>
+ <item quantity="other">Displaying <xliff:g id="count">%d</xliff:g> contacts</item>
+ </plurals>
+
+ <!-- Displayed at the top of the contacts showing the zero total number of contacts visible when "Only contacts with phones" not selected -->
+ <string name="listTotalAllContactsZero">No visible contacts</string>
+
+ <!-- Displayed at the top of the contacts showing the total number of contacts found when "Only contacts with phones" not selected -->
+ <plurals name="listFoundAllContacts">
+ <item quantity="one">Found 1 contact</item>
+ <item quantity="other">Found <xliff:g id="count">%d</xliff:g> contacts</item>
+ </plurals>
+
+ <!-- Displayed at the top of the contacts showing the zero total number of contacts found when "Only contacts with phones" not selected -->
+ <string name="listFoundAllContactsZero">Contact not found</string>
+
+ <!-- The description text for the social activity stream tab. Space is limited for this string, so the shorter the better -->
+ <string name="socialStreamIconLabel">Social</string>
+
<!-- The description text for the contacts tab. Space is limited for this string, so the shorter the better -->
<string name="contactsIconLabel">Contacts</string>
@@ -328,7 +474,7 @@
<string name="contactsFavoritesLabel">Favorites</string>
<!-- The description text for the dialer tab. Space is limited for this string, so the shorter the better -->
- <string name="dialerIconLabel">Dialer</string>
+ <string name="dialerIconLabel">Phone</string>
<!-- The description text for the call log tab. Space is limited for this string, so the shorter the better -->
<string name="recentCallsIconLabel">Call log</string>
@@ -337,7 +483,7 @@
<string name="liveFolderPhone">Contacts with phone numbers</string>
<!-- Menu item used to send an SMS or MMS message to a phone number -->
- <string name="menu_sendTextMessage">Send SMS message</string>
+ <string name="menu_sendTextMessage">Send text message</string>
<!-- Menu item used to call a contact from the call log -->
<string name="recentCalls_callNumber">Call <xliff:g id="name">%s</xliff:g></string>
@@ -360,6 +506,9 @@
<!-- The title of a dialog that displays the IMEI of the phone -->
<string name="imei">IMEI</string>
+ <!-- The title of a dialog that displays the MEID of the CDMA phone -->
+ <string name="meid">MEID</string>
+
<!-- String used for displaying calls to the voicemail number in the call log -->
<string name="voicemail">Voicemail</string>
@@ -368,7 +517,7 @@
<!-- String used to display calls from private numbers in the call log -->
<string name="private_num">Private number</string>
-
+
<!-- String used to display calls from pay phone in the call log -->
<string name="payphone">Pay phone</string>
@@ -392,30 +541,55 @@
<string name="contactsSyncPlug"><font fgcolor="#ffffffff">Sync your Google contacts!</font>
\nAfter syncing to your phone, your contacts will be available to you wherever you go.</string>
+
<!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is disabled -->
- <string name="noContactsHelpText">"You don't have any contacts.\n\nTo add contacts, press <font fgcolor="#ffffffff"><b>Menu</b></font> and select:\n
+ <string name="noContactsHelpText">"You don't have any contacts to display.\n\nTo add contacts, press <font fgcolor="#ffffffff"><b>Menu</b></font> and touch:\n
+ \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or configure an account with contacts you can sync to the phone\n</li>
\n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Import contacts</b></font> to add contacts from your SIM card\n</li>"
+ \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font>\n</li>"
</string>
-
+
<!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is enabled -->
- <string name="noContactsHelpTextWithSync">"You don't have any contacts.\n\nTo add contacts, press <font fgcolor="#ffffffff"><b>Menu</b></font> and select:\n
- \n<li><font fgcolor="#ffffffff"><b>Edit sync groups</b></font> to add from a new or existing Google account\n</li>
+ <string name="noContactsHelpTextWithSync">"You don't have any contacts to display. (If you just added an account, it can take a few minutes to sync contacts.)\n\nTo add contacts, press <font fgcolor="#ffffffff"><b>Menu</b></font> and touch:\n
+ \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or configure an account with contacts you can sync to the phone\n</li>
+ \n<li><font fgcolor="#ffffffff"><b>Display options</b></font> to change which contacts are visible\n</li>
\n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
- \n<li><font fgcolor="#ffffffff"><b>Import contacts</b></font> to add contacts from your SIM card\n</li>"
+ \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font>\n</li>"
+ </string>
+
+ <!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is disabled, and there is no sim card (cdma)-->
+ <string name="noContactsNoSimHelpText">"You don't have any contacts to display.\n\nTo add contacts, press <font fgcolor="#ffffffff"><b>Menu</b></font> and touch:\n
+ \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or configure an account with contacts you can sync to the phone\n</li>
+ \n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
+ \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font>\n</li>"
+ </string>
+
+ <!-- Displayed full screen when the user has no contacts and they are displaying the My Contacts group, and contact syncing is enabled, and there is no sim card (cdma) -->
+ <string name="noContactsNoSimHelpTextWithSync">"You don't have any contacts to display. (If you just added an account, it can take a few minutes to sync contacts.)\n\nTo add contacts, press <font fgcolor="#ffffffff"><b>Menu</b></font> and touch:\n
+ \n<li><font fgcolor="#ffffffff"><b>Accounts</b></font> to add or configure an account with contacts you can sync to the phone\n</li>
+ \n<li><font fgcolor="#ffffffff"><b>Display options</b></font> to change which contacts are visible\n</li>
+ \n<li><font fgcolor="#ffffffff"><b>New contact</b></font> to create a new contact from scratch\n</li>
+ \n<li><font fgcolor="#ffffffff"><b>Import/Export</b></font>\n</li>"
+ </string>
+
+ <!-- Displayed full screen when the user has no favorites and they are displaying the favorites tab -->
+ <string name="noFavoritesHelpText">"You don't have any favorites.\n\nTo add a contact to your list of favorites:\n
+ <li>Touch the <b>Contacts</b> tab\n</li>
+ \n<li>Touch the contact you want to add to your favorites\n</li>
+ \n<li>Touch the star next to the contact\'s name\n</li>"
</string>
<!-- Activity title for the activity that lets the user choose which groups of contacts to sync from the server -->
<string name="seclectSyncGroups_title">Select groups to sync</string>
<!-- Live folder label for all contacts -->
- <string name="liveFolder_all_label">All Contacts</string>
+ <string name="liveFolder_all_label">All contacts</string>
<!-- Live folder label for only starred contacts -->
<string name="liveFolder_favorites_label">Starred</string>
<!-- Live folder label for all contacts with phone numbers -->
- <string name="liveFolder_phones_label">Phones</string>
+ <string name="liveFolder_phones_label">Phones</string>
<!-- Item label: jump to the in-call DTMF dialpad.
(Part of a list of options shown in the dialer when another call
@@ -443,7 +617,7 @@
<!-- Title for incoming call details screen -->
<string name="type_incoming">Incoming call</string>
-
+
<!-- Title for outgoing call details screen -->
<string name="type_outgoing">Outgoing call</string>
@@ -485,13 +659,13 @@
<!-- Description for incoming calls going to voice mail vs. not -->
<string name="actionIncomingCall">Incoming calls</string>
-
+
<!-- Detail text for incoming calls going to voice mail -->
<string name="detailIncomingCallsGoToVoicemail">Will be sent directly to voicemail</string>
<!-- Description of what the contact specific ringtone is set to -->
<string name="detailsRingtone">Set to <xliff:g id="ringtone_name" example="Flutey Phone">%s</xliff:g></string>
-
+
<!-- Action string for calling back a number in the call log -->
<string name="callBack">Call back</string>
@@ -508,11 +682,14 @@
<string name="favoritesFrquentSeparator">Frequently called</string>
<!-- Dialog title when prompting before creating a contact -->
- <string name="add_contact_dlg_title">Add Contact</string>
+ <string name="add_contact_dlg_title">Add contact</string>
<!-- Dialog message when prompting before creating a contact. Includes
the email address, e.g. "Add xyz@foo.com to contacts?" -->
<string name="add_contact_dlg_message_fmt">Add \"<xliff:g id="email">%s</xliff:g>\" to contacts?</string>
+ <!-- Label for the all data tab in the view and edit card -->
+ <string name="all_tab_label">All</string>
+
<!-- Content description values -->
<!-- String describing the image on ImageButton one
@@ -600,70 +777,91 @@
<string name="description_image_button_pound">pound</string>
<!-- Dialog title shown when SD Card does not exist -->
- <string name="no_sdcard_title">No SD Card</string>
+ <string name="no_sdcard_title">No SD card</string>
<!-- Dialog message shown when SDcard does not exist -->
- <string name="no_sdcard_message">No SD Card detected</string>
+ <string name="no_sdcard_message">No SD card detected</string>
<!-- Dialog title shown when searching VCard data from SD Card -->
- <string name="searching_vcard_title">Searching for VCard</string>
+ <string name="searching_vcard_title">Searching for vCard</string>
<!-- Dialog title shown when asking a user whether import contact data from SIM or SD Card -->
<string name="select_import_type_title">Where would you like to import contacts from?</string>
<!-- Action string for selecting SIM for importing contacts -->
- <string name="import_from_sim">SIM Card</string>
+ <string name="import_from_sim">Import from SIM card</string>
<!-- Action string for selecting SD Card for importing contacts -->
- <string name="import_from_sdcard">SD Card</string>
+ <string name="import_from_sdcard">Import from SD card</string>
- <!-- "Import all VCard files" -->
- <string name="import_all_vcard_string">Import all VCard files</string>
+ <!-- Action that exports all contacts to SD Card -->
+ <string name="export_to_sdcard">Export to SD card</string>
- <!-- "Import one VCard file" -->
- <string name="import_one_vcard_string">Import one VCard file</string>
+ <!-- "Import one vCard file" -->
+ <string name="import_one_vcard_string">Import one vCard file</string>
+
+ <!-- "Import more than one vCard -->
+ <string name="import_multiple_vcard_string">Import multiple vCard files</string>
+
+ <!-- "Import all vCard files" -->
+ <string name="import_all_vcard_string">Import all vCard files</string>
<!-- Dialog message shown when searching VCard data from SD Card -->
- <string name="searching_vcard_message">Searching for VCard data on VCard</string>
+ <string name="searching_vcard_message">Searching for vCard data on SD card</string>
<!-- Dialog title shown when searching VCard data failed. -->
- <string name="scanning_sdcard_failed_title">Scanning SD Card failed</string>
+ <string name="scanning_sdcard_failed_title">Scanning SD card failed</string>
<!-- Dialog message shown when searching VCard data failed. -->
- <string name="scanning_sdcard_failed_message">Scanning SD Card failed</string>
+ <string name="scanning_sdcard_failed_message">Scanning SD card failed (Reason: \"<xliff:g id="fail_reason">%s</xliff:g>\")</string>
<!-- The failed reason: "I/O Error" -->
<string name="fail_reason_io_error">I/O Error</string>
<!-- The failed reason: "Failed to parse VCard data" -->
- <string name="fail_reason_vcard_parse_error">Failed to parse VCard</string>
+ <string name="fail_reason_vcard_parse_error">Failed to parse vCard for unexpected reason</string>
+
+ <!-- The failed reason: "The VCard is not supported right now, but may be supported in the future" -->
+ <string name="fail_reason_vcard_not_supported_error">Failed to parse vCard though it seems in valid format, since the current implementation does not support it</string>
<!-- The failed reason: "There is no VCard file" -->
- <string name="fail_reason_no_vcard_file">No VCard file found on SD Card</string>
+ <string name="fail_reason_no_vcard_file">No vCard file found on the SD card</string>
<!-- The failed reason: "There is no valid VCard entry in the file(s)" -->
- <string name="fail_reason_no_vcard_entry">No valid VCard entry found for your selection</string>
+ <string name="fail_reason_no_vcard_entry">No valid vCard entry found for your selection</string>
+
+ <!-- The failed reason: "One or more files failed to be imported. (<a list of file names>)" -->
+ <string name="fail_reason_failed_to_read_files">One or more files failed to be imported (%s).</string>
+
+ <!-- The failed reason: "Unknown error". This message should not be shown
+ but it may in some buggy condition. -->
+ <string name="fail_reason_unknown">Unknown error</string>
<!-- Dialog title shown when a user is asked to select VCard file -->
- <string name="select_vcard_title">Select VCard file</string>
+ <string name="select_vcard_title">Select vCard file</string>
<!-- Dialog message shown when a user is asked to choose VCard file -->
- <string name="select_vcard_message">Please select a VCard file to import</string>
+ <string name="select_vcard_message">Please select a vCard file to import</string>
+
+ <!-- The message shown while reading a vCard file/entry. The first argument is like
+ "Reading VCard" or "Reading VCard files" and the second is the display name of the current
+ data being parsed -->
+ <string name="progress_shower_message"><xliff:g id="action" example="Reading VCard">%s</xliff:g>\n<xliff:g id="filename" example="foo.vcf">%s</xliff:g></string>
<!-- Dialog title shown when reading VCard data -->
- <string name="reading_vcard_title">Reading VCard</string>
+ <string name="reading_vcard_title">Reading vCard</string>
<!-- Dialog message shown when reading a VCard file -->
- <string name="reading_vcard_message">Reading VCard file(s)</string>
+ <string name="reading_vcard_message">Reading vCard file(s)</string>
<!-- Dialog message shown when importing VCard data into local database -->
- <string name="importing_vcard_message">Importing VCard data</string>
+ <string name="importing_vcard_message">Importing vCard data</string>
<!-- Dialog title shown when reading VCard data failed -->
- <string name="reading_vcard_failed_title">Reading of VCard data has failed</string>
+ <string name="reading_vcard_failed_title">Reading of vCard data has failed</string>
<!-- Dialog message shown when reading VCard data failed -->
- <string name="reading_vcard_failed_message">VCard data could not be read\nReason for failure: \"<xliff:g id="fail_reason">%s</xliff:g>\"</string>
+ <string name="reading_vcard_failed_message">Could not read vCard.\nReason for failure: \"<xliff:g id="fail_reason">%s</xliff:g>\"</string>
<!-- Message while reading one vCard file "(current number) of (total number) contacts" The order of "current number" and "total number" cannot be changed (like "total: (total number), current: (current number)")-->
<string name="reading_vcard_contacts"><xliff:g id="current_number">%s</xliff:g> of <xliff:g id="total_number">%s</xliff:g> contacts</string>
@@ -671,26 +869,35 @@
<!-- Message while reading multiple vCard files "(current number) of (total number) files" The order of "current number" and "total number" cannot be changed (like "total: (total number), current: (current number)")-->
<string name="reading_vcard_files"><xliff:g id="current_number">%s</xliff:g> of <xliff:g id="total_number">%s</xliff:g> files</string>
+ <!-- The message for exporting all contacts in the phone, without caring its Account -->
+ <string name="export_all_contacts">All contacts</string>
+
+ <!-- The message for exporting only contacts is the phone locally, which are not associated with any account -->
+ <string name="export_phone_local_only">Locally stored contacts</string>
+
<!-- The menu item that launches VCard export activity -->
<string name="export_contact_list">Export contacts</string>
-
+
<!-- Dialog title shown when a user confirms whether he/she export Contact data -->
- <string name="confirm_export_title">Confirmation for export</string>
-
+ <string name="confirm_export_title">Confirm export</string>
+
<!-- Dialog message shown when a user confirms whether he/she export Contact data -->
- <string name="confirm_export_message">Is it ok to export your contact list to \"<xliff:g id="vcard_filename">%s</xliff:g>\"?</string>
-
+ <string name="confirm_export_message">Are you sure you want to export your contact list to \"<xliff:g id="vcard_filename">%s</xliff:g>\"?</string>
+
<!-- Dialog title shown when exporting Contact data failed -->
- <string name="exporting_contact_failed_title">Exporting contact data has failed</string>
-
+ <string name="exporting_contact_failed_title">Failed to export contact data</string>
+
<!-- Dialog message shown when exporting Contact data failed -->
- <string name="exporting_contact_failed_message">Exporting contact data has failed\nReason for failure: \"<xliff:g id="fail_reason">%s</xliff:g>\"</string>
+ <string name="exporting_contact_failed_message">Failed to export contact data.\nReason for failure: \"<xliff:g id="fail_reason">%s</xliff:g>\"</string>
+
+ <!-- The failed reason: "There is no exportable contact" -->
+ <string name="fail_reason_no_exportable_contact">There is no exportable contact</string>
<!-- The failed reason: "Too many vcard files on the SD Card" -->
- <string name="fail_reason_too_many_vcard">Too many VCard data on the SD Card</string>
+ <string name="fail_reason_too_many_vcard">Too many vCard files on the SD card</string>
<!-- The failed reason: "Too long filename". This error usually does not happen. -->
- <string name="fail_reason_too_long_filename">Too long filename is required (\"<xliff:g id="filename">%s</xliff:g>\")</string>
+ <string name="fail_reason_too_long_filename">Required filename is too long (\"<xliff:g id="filename">%s</xliff:g>\")</string>
<!-- The failed reason: "Cannot open or create the destination directory" -->
<string name="fail_reason_cannot_open_destination_dir">Cannot open or create the destination directory\"<xliff:g id="dir_name">%s</xliff:g>\"</string>
@@ -700,19 +907,314 @@
<!-- Message shown when the application is exporting contact data outside -->
<string name="exporting_contact_list_message">Exporting contact data to \"<xliff:g id="file_name">%s</xliff:g>\"</string>
-
+
<!-- The failed reason: "Could not initialize the exporter" -->
<string name="fail_reason_could_not_initialize_exporter">Could not initialize the exporter: \"<xliff:g id="exact_reason">%s</xliff:g>\"</string>
-
+
<!-- The failed reason: "Error occured during export" -->
<string name="fail_reason_error_occurred_during_export">Error occured during export: \"<xliff:g id="exact_reason">%s</xliff:g>\"</string>
-
+
+ <!-- The error reason the vCard composer emits: "Failed to get database information" -->
+ <string name="composer_failed_to_get_database_infomation">Failed to get database information</string>
+
+ <!-- The error reason the vCard composer emits: "There is no exportable contact. You might choose un-exportable data" -->
+ <string name="composer_has_no_exportable_contact">There is no exportable contact. You might choose un-exportable data</string>
+
+ <!-- The error reason the vCard composer emits: "The vCard composer object is not correctly initialized" -->
+ <string name="composer_not_initialized">The vCard composer is not correctly initialized</string>
+
<!-- The failed reason: "Could not open a specific file" -->
<string name="fail_reason_could_not_open_file">Could not open \"<xliff:g id="file_name">%s</xliff:g>\": <xliff:g id="exact_reason">%s</xliff:g></string>
<!-- Message in progress bar while exporting contact list to a file "(current number) of (total number) contacts" The order of "current number" and "total number" cannot be changed (like "total: (total number), current: (current number)")-->
<string name="exporting_contact_list_progress"><xliff:g id="current_number">%s</xliff:g> of <xliff:g id="total_number">%s</xliff:g> contacts</string>
-
+
<!-- The string used to describe Contacts as a searchable item within system search settings. -->
<string name="search_settings_description">Names of your contacts</string>
-</resources>
\ No newline at end of file
+
+ <!-- Menu items for dialpad options as part of Pause and Wait ftr -->
+ <string name="add_2sec_pause">Add 2-sec pause</string>
+ <string name="add_wait">Add wait</string>
+
+ <!-- Label for onscreen "Dial" button -->
+ <string name="dial_button_label">Dial</string>
+
+ <!-- Title for the call disambiguation dialog -->
+ <string name="call_disambig_title">Call using</string>
+
+ <!-- Title for the sms disambiguation dialog -->
+ <string name="sms_disambig_title">Text using</string>
+
+ <!-- Message next to disamgiguation dialog check box -->
+ <string name="make_primary">Remember this choice</string>
+
+ <!-- Shown as a toast when the user taps on a Fast-Track icon, and no application
+ was found that could perform the selected action -->
+ <string name="quickcontact_missing_app">No application found to handle this action</string>
+
+ <!-- Shown as the checkbox label that, when checked, will store remember the
+ selected choice and shortcut to it in the future. For example, this would
+ make a selected phone number the default. -->
+ <string name="quickcontact_remember_choice">Remember this choice</string>
+
+ <!-- Shown as the header name for a person when the name is missing or unknown. -->
+ <string name="quickcontact_missing_name">Unknown</string>
+
+ <!-- The menu item to open the list of accounts -->
+ <string name="menu_accounts">Accounts</string>
+
+ <!-- The menu item to bulk import or bulk export contacts from SIM card or SD card. -->
+ <string name="menu_import_export">Import/Export</string>
+
+ <!-- Dialog title when selecting the bulk operation to perform from a list. -->
+ <string name="dialog_import_export">Import/Export contacts</string>
+
+ <!-- The menu item to share the currently viewed contact -->
+ <string name="menu_share">Share</string>
+
+ <!-- Dialog title when picking the application to share a contact with. -->
+ <string name="share_via">Share contact via</string>
+
+ <!-- Toast indicating that sharing a contact has failed. -->
+ <string name="share_error">This contact cannot be shared.</string>
+
+ <!-- Header that expands to list all name types when editing a structured name of a contact -->
+ <string name="nameLabelsGroup">Name</string>
+ <!-- Header that expands to list all nickname types when editing a nickname of a contact -->
+ <string name="nicknameLabelsGroup">Nickname</string>
+ <!-- Header that expands to list all organization types when editing an organization of a contact -->
+ <string name="organizationLabelsGroup">Organization</string>
+ <!-- Header that expands to list all website types when editing a website of a contact -->
+ <string name="websiteLabelsGroup">Website</string>
+ <!-- Header that expands to list all event types when editing an event of a contact -->
+ <string name="eventLabelsGroup">Event</string>
+
+ <!-- Single-character overlay for home phone numbers when creating desktop shortcuts -->
+ <string name="type_short_home">H</string>
+ <!-- Single-character overlay for mobile phone numbers when creating desktop shortcuts -->
+ <string name="type_short_mobile">M</string>
+ <!-- Single-character overlay for work phone numbers when creating desktop shortcuts -->
+ <string name="type_short_work">W</string>
+ <!-- Single-character overlay for pager phone numbers when creating desktop shortcuts -->
+ <string name="type_short_pager">P</string>
+ <!-- Single-character overlay for other phone numbers when creating desktop shortcuts -->
+ <string name="type_short_other">O</string>
+
+ <!-- In edit dialog, shown if the contact is marked as being read-only -->
+ <string name="edit_read_only">This contact is read-only</string>
+
+ <!-- Shown as the header title over a collapsible section that, by default, hides
+ secondary contact detail edit fields, such as birthday. -->
+ <string name="edit_secondary_collapse">More</string>
+
+ <string name="dialog_primary_name">Primary name</string>
+ <string name="dialog_new_contact_account">Create contact under account</string>
+
+ <string name="menu_sync_remove">Remove sync group</string>
+ <string name="dialog_sync_add">Add sync group</string>
+ <string name="display_more_groups">More groups\u2026</string>
+
+ <!-- List title for a special contacts group that covers all contacts.-->
+ <string name="display_ungrouped">All Other Contacts</string>
+
+ <!-- List title for a special contacts group that covers all contacts that
+ aren't members of any other group. -->
+ <string name="display_all_contacts">All Contacts</string>
+
+ <!-- Warning message given to users just before they remove a currently syncing
+ group that would also cause all ungrouped contacts to stop syncing. -->
+ <string name="display_warn_remove_ungrouped">Removing \'<xliff:g id="group" example="Starred">%s</xliff:g>\' from sync will also remove any ungrouped contacts from sync.</string>
+
+ <!-- Title for data source when creating or editing a contact that doesn't
+ belong to a specific account. This contact will only exist on the phone
+ and will not be synced. -->
+ <string name="account_phone">Phone-only (unsynced)</string>
+
+ <!-- The label describing the display name field of an Email address, allowing the
+ user to give a specific name to describe this address. -->
+ <string name="label_email_display_name">Display name</string>
+
+ <!-- Action string for calling a custom phone number -->
+ <string name="call_custom">Call <xliff:g id="custom">%s</xliff:g></string>
+ <!-- Action string for calling a home phone number -->
+ <string name="call_home">Call home</string>
+ <!-- Action string for calling a mobile phone number -->
+ <string name="call_mobile">Call mobile</string>
+ <!-- Action string for calling a work phone number -->
+ <string name="call_work">Call work</string>
+ <!-- Action string for calling a work fax phone number -->
+ <string name="call_fax_work">Call work fax</string>
+ <!-- Action string for calling a home fax phone number -->
+ <string name="call_fax_home">Call home fax</string>
+ <!-- Action string for calling a pager phone number -->
+ <string name="call_pager">Call pager</string>
+ <!-- Action string for calling an other phone number -->
+ <string name="call_other">Call other</string>
+ <!-- Action string for calling a callback number -->
+ <string name="call_callback">Call callback</string>
+ <!-- Action string for calling a car phone number -->
+ <string name="call_car">Call car</string>
+ <!-- Action string for calling a company main phone number -->
+ <string name="call_company_main">Call company main</string>
+ <!-- Action string for calling a ISDN phone number -->
+ <string name="call_isdn">Call ISDN</string>
+ <!-- Action string for calling a main phone number -->
+ <string name="call_main">Call main</string>
+ <!-- Action string for calling an other fax phone number -->
+ <string name="call_other_fax">Call other fax</string>
+ <!-- Action string for calling a radio phone number -->
+ <string name="call_radio">Call radio</string>
+ <!-- Action string for calling a Telex phone number -->
+ <string name="call_telex">Call telex</string>
+ <!-- Action string for calling a TTY/TDD phone number -->
+ <string name="call_tty_tdd">Call TTY/TDD</string>
+ <!-- Action string for calling a work mobile phone number -->
+ <string name="call_work_mobile">Call work mobile</string>
+ <!-- Action string for calling a work pager phone number -->
+ <string name="call_work_pager">Call work pager</string>
+ <!-- Action string for calling an assistant phone number -->
+ <string name="call_assistant">Call <xliff:g id="assistant">%s</xliff:g></string>
+ <!-- Action string for calling a MMS phone number -->
+ <string name="call_mms">Call MMS</string>
+
+ <!-- Action string for sending an SMS to a custom phone number -->
+ <string name="sms_custom">Text <xliff:g id="custom">%s</xliff:g></string>
+ <!-- Action string for sending an SMS to a home phone number -->
+ <string name="sms_home">Text home</string>
+ <!-- Action string for sending an SMS to a mobile phone number -->
+ <string name="sms_mobile">Text mobile</string>
+ <!-- Action string for sending an SMS to a work phone number -->
+ <string name="sms_work">Text work</string>
+ <!-- Action string for sending an SMS to a work fax phone number -->
+ <string name="sms_fax_work">Text work fax</string>
+ <!-- Action string for sending an SMS to a home fax phone number -->
+ <string name="sms_fax_home">Text home fax</string>
+ <!-- Action string for sending an SMS to a pager phone number -->
+ <string name="sms_pager">Text pager</string>
+ <!-- Action string for sending an SMS to an other phone number -->
+ <string name="sms_other">Text other</string>
+ <!-- Action string for sending an SMS to a callback number -->
+ <string name="sms_callback">Text callback</string>
+ <!-- Action string for sending an SMS to a car phone number -->
+ <string name="sms_car">Text car</string>
+ <!-- Action string for sending an SMS to a company main phone number -->
+ <string name="sms_company_main">Text company main</string>
+ <!-- Action string for sending an SMS to a ISDN phone number -->
+ <string name="sms_isdn">Text ISDN</string>
+ <!-- Action string for sending an SMS to a main phone number -->
+ <string name="sms_main">Text main</string>
+ <!-- Action string for sending an SMS to an other fax phone number -->
+ <string name="sms_other_fax">Text other fax</string>
+ <!-- Action string for sending an SMS to a radio phone number -->
+ <string name="sms_radio">Text radio</string>
+ <!-- Action string for sending an SMS to a Telex phone number -->
+ <string name="sms_telex">Text telex</string>
+ <!-- Action string for sending an SMS to a TTY/TDD phone number -->
+ <string name="sms_tty_tdd">Text TTY/TDD</string>
+ <!-- Action string for sending an SMS to a work mobile phone number -->
+ <string name="sms_work_mobile">Text work mobile</string>
+ <!-- Action string for sending an SMS to a work pager phone number -->
+ <string name="sms_work_pager">Text work pager</string>
+ <!-- Action string for sending an SMS to an assistant phone number -->
+ <string name="sms_assistant">Text <xliff:g id="assistant">%s</xliff:g></string>
+ <!-- Action string for sending an SMS to a MMS phone number -->
+ <string name="sms_mms">Text MMS</string>
+
+ <!-- Action string for sending an email to a home email address -->
+ <string name="email_home">Email home</string>
+ <!-- Action string for sending an email to a mobile email address -->
+ <string name="email_mobile">Email mobile</string>
+ <!-- Action string for sending an email to a work email address -->
+ <string name="email_work">Email work</string>
+ <!-- Action string for sending an email to an other email address -->
+ <string name="email_other">Email other</string>
+ <!-- Action string for sending an email to a custom email address -->
+ <string name="email_custom">Email <xliff:g id="custom">%s</xliff:g></string>
+
+ <!-- Generic action string for sending an email -->
+ <string name="email">Email</string>
+
+ <!-- Action string for viewing a home postal address -->
+ <string name="map_home">View home address</string>
+ <!-- Action string for viewing a work postal address -->
+ <string name="map_work">View work address</string>
+ <!-- Action string for viewing an other postal address -->
+ <string name="map_other">View other address</string>
+ <!-- Action string for viewing a custom postal address -->
+ <string name="map_custom">View <xliff:g id="custom">%s</xliff:g> address</string>
+
+ <!-- Action string for starting an IM chat with the AIM protocol -->
+ <string name="chat_aim">Chat using AIM</string>
+ <!-- Action string for starting an IM chat with the MSN or Windows Live protocol -->
+ <string name="chat_msn">Chat using Windows Live</string>
+ <!-- Action string for starting an IM chat with the Yahoo protocol -->
+ <string name="chat_yahoo">Chat using Yahoo</string>
+ <!-- Action string for starting an IM chat with the Skype protocol -->
+ <string name="chat_skype">Chat using Skype</string>
+ <!-- Action string for starting an IM chat with the QQ protocol -->
+ <string name="chat_qq">Chat using QQ</string>
+ <!-- Action string for starting an IM chat with the Google Talk protocol -->
+ <string name="chat_gtalk">Chat using Google Talk</string>
+ <!-- Action string for starting an IM chat with the ICQ protocol -->
+ <string name="chat_icq">Chat using ICQ</string>
+ <!-- Action string for starting an IM chat with the Jabber protocol -->
+ <string name="chat_jabber">Chat using Jabber</string>
+
+ <!-- Generic action string for starting an IM chat -->
+ <string name="chat">Chat</string>
+
+ <!-- Field title for the street of a structured postal address of a contact -->
+ <string name="postal_street">Street</string>
+ <!-- Field title for the PO box of a structured postal address of a contact -->
+ <string name="postal_pobox">PO box</string>
+ <!-- Field title for the neighborhood of a structured postal address of a contact -->
+ <string name="postal_neighborhood">Neighborhood</string>
+ <!-- Field title for the city of a structured postal address of a contact -->
+ <string name="postal_city">City</string>
+ <!-- Field title for the region, or state, of a structured postal address of a contact -->
+ <string name="postal_region">State</string>
+ <!-- Field title for the postal code of a structured postal address of a contact -->
+ <string name="postal_postcode">ZIP code</string>
+ <!-- Field title for the country of a structured postal address of a contact -->
+ <string name="postal_country">Country</string>
+
+ <!-- Field title for the given name of a contact -->
+ <string name="name_given">Given name</string>
+ <!-- Field title for the family name of a contact -->
+ <string name="name_family">Family name</string>
+ <!-- Field title for the prefix name of a contact -->
+ <string name="name_prefix">Name prefix</string>
+ <!-- Field title for the middle name of a contact -->
+ <string name="name_middle">Middle name</string>
+ <!-- Field title for the suffix name of a contact -->
+ <string name="name_suffix">Name suffix</string>
+ <!-- Field title for the phonetic given name of a contact -->
+ <string name="name_phonetic_given">Phonetic given name</string>
+ <!-- Field title for the phonetic middle name of a contact -->
+ <string name="name_phonetic_middle">Phonetic middle name</string>
+ <!-- Field title for the phonetic family name of a contact -->
+ <string name="name_phonetic_family">Phonetic family name</string>
+
+ <!-- The title for the action to remove a contact from an aggregated contact -->
+ <string name="split_label">Split</string>
+ <!-- The explanation of what "split" will do. This needs word-smithing. -->
+ <string name="split_explanation">Make this data its own contact.</string>
+
+ <!-- Formatting string for account name -->
+ <string name="account_name_format">From <xliff:g id="source" example="Gmail">%1$s</xliff:g> account: <xliff:g id="account" example="user@gmail.com">%2$s</xliff:g></string>
+
+ <!-- String describing which account type a contact came from when editing it -->
+ <string name="account_type_format"><xliff:g id="source" example="Gmail">%1$s</xliff:g> contact</string>
+
+ <!-- String describing which account a contact came from when editing it -->
+ <string name="from_account_format">from <xliff:g id="source" example="user@gmail.com">%1$s</xliff:g></string>
+
+ <!-- Checkbox asking the user if they want to display a particular photo for a contact -->
+ <string name="use_photo_as_primary">Use this photo</string>
+
+ <!-- Text used to explain that a contact cannot be edited since the data is read only -->
+ <string name="contact_read_only"><xliff:g id="source" example="Gmail">%1$s</xliff:g> contact information is not editable on this device.</string>
+
+ <!-- Text describing that a contact has no information available other than name and photo -->
+ <string name="no_contact_details">No additional information for this contact</string>
+</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 998da21..8c5ae35 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -4,9 +4,9 @@
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.
@@ -15,6 +15,10 @@
-->
<resources>
+ <style name="DialtactsTheme" parent="@android:Theme">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
<style name="MinusButton">
<item name="android:background">@drawable/btn_circle</item>
@@ -44,4 +48,41 @@
<item name="android:windowIsFloating">true</item>
</style>
+ <style name="FullyTranslucent" parent="android:Theme.Translucent.NoTitleBar">
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
+ <style name="FullyTranslucent.QuickContact">
+ <!-- This is a hack because we want to be able to animate away the
+ QuickContact window, and we close its containing activity at the
+ same time. So put in a dummy animation so this guy sticks around
+ while the fast track window is animating. -->
+ <item name="android:windowAnimationStyle">@style/DummyAnimation</item>
+ </style>
+
+ <style name="QuickContact">
+ <item name="android:windowFrame">@null</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <!-- TODO: create our own animation style in framework -->
+ <!--
+ <item name="android:windowAnimationStyle">@*android:style/Animation.ZoomButtons</item>
+ -->
+ </style>
+
+ <style name="QuickContactAboveAnimation">
+ <item name="android:windowEnterAnimation">@anim/quickcontact_above_enter</item>
+ <item name="android:windowExitAnimation">@anim/quickcontact_above_exit</item>
+ </style>
+
+ <style name="QuickContactBelowAnimation">
+ <item name="android:windowEnterAnimation">@anim/quickcontact_below_enter</item>
+ <item name="android:windowExitAnimation">@anim/quickcontact_below_exit</item>
+ </style>
+
+ <style name="DummyAnimation">
+ <item name="android:windowExitAnimation">@anim/dummy_animation</item>
+ </style>
+
</resources>
diff --git a/res/xml/searchable.xml b/res/xml/searchable.xml
index 0deed7e..af8b3ef 100644
--- a/res/xml/searchable.xml
+++ b/res/xml/searchable.xml
@@ -25,9 +25,9 @@
android:searchMode="queryRewriteFromText"
android:includeInGlobalSearch="true"
- android:searchSuggestAuthority="contacts"
+ android:searchSuggestAuthority="com.android.contacts"
android:searchSuggestIntentAction="android.provider.Contacts.SEARCH_SUGGESTION_CLICKED"
- android:searchSuggestIntentData="content://contacts/people"
+ android:searchSuggestIntentData="content://com.android.contacts/contacts"
android:searchSettingsDescription="@string/search_settings_description"
>
diff --git a/src/com/android/contacts/AttachImage.java b/src/com/android/contacts/AttachImage.java
index 8c91722..6970842 100644
--- a/src/com/android/contacts/AttachImage.java
+++ b/src/com/android/contacts/AttachImage.java
@@ -16,15 +16,32 @@
package com.android.contacts;
+import com.google.android.collect.Maps;
+
import android.app.Activity;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
import android.content.Intent;
+import android.content.OperationApplicationException;
+import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
-import android.provider.Contacts;
-import android.provider.Contacts.People;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.widget.Toast;
+
+import com.android.contacts.model.ExchangeSource;
+import com.android.contacts.model.GoogleSource;
import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
/**
* Provides an external interface for other applications to attach images
@@ -36,36 +53,62 @@
private static final int REQUEST_PICK_CONTACT = 1;
private static final int REQUEST_CROP_PHOTO = 2;
- private static final String CONTACT_URI_KEY = "contact_uri";
+ private static final String RAW_CONTACT_URIS_KEY = "raw_contact_uris";
public AttachImage() {
}
- Uri mContactUri;
+ private Long[] mRawContactIds;
+
+ private ContentResolver mContentResolver;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
if (icicle != null) {
- mContactUri = icicle.getParcelable(CONTACT_URI_KEY);
+ mRawContactIds = toClassArray(icicle.getLongArray(RAW_CONTACT_URIS_KEY));
} else {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.setType(People.CONTENT_ITEM_TYPE);
+ intent.setType(Contacts.CONTENT_ITEM_TYPE);
startActivityForResult(intent, REQUEST_PICK_CONTACT);
}
+
+ mContentResolver = getContentResolver();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- if (mContactUri != null) {
- outState.putParcelable(CONTACT_URI_KEY, mContactUri);
+ if (mRawContactIds != null && mRawContactIds.length != 0) {
+ outState.putLongArray(RAW_CONTACT_URIS_KEY, toPrimativeArray(mRawContactIds));
}
}
+ private static long[] toPrimativeArray(Long[] in) {
+ if (in == null) {
+ return null;
+ }
+ long[] out = new long[in.length];
+ for (int i = 0; i < in.length; i++) {
+ out[i] = in[i];
+ }
+ return out;
+ }
+
+ private static Long[] toClassArray(long[] in) {
+ if (in == null) {
+ return null;
+ }
+ Long[] out = new Long[in.length];
+ for (int i = 0; i < in.length; i++) {
+ out[i] = in[i];
+ }
+ return out;
+ }
+
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent result) {
if (resultCode != RESULT_OK) {
@@ -74,7 +117,6 @@
}
if (requestCode == REQUEST_PICK_CONTACT) {
- mContactUri = result.getData();
// A contact was picked. Launch the cropper to get face detection, the right size, etc.
// TODO: get these values from constants somewhere
Intent myIntent = getIntent();
@@ -89,18 +131,120 @@
intent.putExtra("outputY", 96);
intent.putExtra("return-data", true);
startActivityForResult(intent, REQUEST_CROP_PHOTO);
+
+ // while they're cropping, convert the contact into a raw_contact
+ final long contactId = ContentUris.parseId(result.getData());
+ final ArrayList<Long> rawContactIdsList = ContactsUtils.queryForAllRawContactIds(
+ mContentResolver, contactId);
+ mRawContactIds = new Long[rawContactIdsList.size()];
+ mRawContactIds = rawContactIdsList.toArray(mRawContactIds);
+
+ if (mRawContactIds == null || rawContactIdsList.isEmpty()) {
+ Toast.makeText(this, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
+ }
} else if (requestCode == REQUEST_CROP_PHOTO) {
final Bundle extras = result.getExtras();
- if (extras != null) {
+ if (extras != null && mRawContactIds != null) {
Bitmap photo = extras.getParcelable("data");
if (photo != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.JPEG, 75, stream);
- Contacts.People.setPhotoData(getContentResolver(), mContactUri,
- stream.toByteArray());
+
+ final ContentValues imageValues = new ContentValues();
+ imageValues.put(Photo.PHOTO, stream.toByteArray());
+ imageValues.put(RawContacts.Data.IS_SUPER_PRIMARY, 1);
+
+ // attach the photo to every raw contact
+ for (Long rawContactId : mRawContactIds) {
+
+ // exchange and google only allow one image, so do an update rather than insert
+ boolean shouldUpdate = false;
+
+ final Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
+ rawContactId);
+ final Uri rawContactDataUri = Uri.withAppendedPath(rawContactUri,
+ RawContacts.Data.CONTENT_DIRECTORY);
+ insertPhoto(imageValues, rawContactDataUri, true);
+ }
}
}
finish();
}
}
+
+ /**
+ * Inserts a photo on the raw contact.
+ * @param values the photo values
+ * @param assertAccount if true, will check to verify if the account is Google or exchange,
+ * no photos exist (Google and exchange only take one picture)
+ */
+ private void insertPhoto(ContentValues values, Uri rawContactDataUri,
+ boolean assertAccount) {
+
+ ArrayList<ContentProviderOperation> operations =
+ new ArrayList<ContentProviderOperation>();
+
+ if (assertAccount) {
+ // make sure for Google and exchange, no pictures exist
+ operations.add(ContentProviderOperation.newAssertQuery(rawContactDataUri)
+ .withSelection(Photo.MIMETYPE + "=? AND "
+ + RawContacts.ACCOUNT_TYPE + " IN (?,?)",
+ new String[] {Photo.CONTENT_ITEM_TYPE, GoogleSource.ACCOUNT_TYPE,
+ ExchangeSource.ACCOUNT_TYPE})
+ .withExpectedCount(0).build());
+ }
+
+ // insert the photo
+ values.put(Photo.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
+ operations.add(ContentProviderOperation.newInsert(rawContactDataUri)
+ .withValues(values).build());
+
+ try {
+ mContentResolver.applyBatch(ContactsContract.AUTHORITY, operations);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Problem querying raw_contacts/data", e);
+ } catch (OperationApplicationException e) {
+ // the account doesn't allow multiple photos, so update
+ if (assertAccount) {
+ updatePhoto(values, rawContactDataUri, false);
+ } else {
+ throw new IllegalStateException("Problem inserting photo into raw_contacts/data", e);
+ }
+ }
+ }
+
+ /**
+ * Tries to update the photo on the raw_contact. If no photo exists, and allowInsert == true,
+ * then will try to {@link #updatePhoto(ContentValues, boolean)}
+ */
+ private void updatePhoto(ContentValues values, Uri rawContactDataUri,
+ boolean allowInsert) {
+ ArrayList<ContentProviderOperation> operations =
+ new ArrayList<ContentProviderOperation>();
+
+ values.remove(Photo.MIMETYPE);
+
+ // check that a photo exists
+ operations.add(ContentProviderOperation.newAssertQuery(rawContactDataUri)
+ .withSelection(Photo.MIMETYPE + "=?", new String[] {
+ Photo.CONTENT_ITEM_TYPE
+ }).withExpectedCount(1).build());
+
+ // update that photo
+ operations.add(ContentProviderOperation.newUpdate(rawContactDataUri).withSelection(Photo.MIMETYPE + "=?", new String[] {
+ Photo.CONTENT_ITEM_TYPE}).withValues(values).build());
+
+ try {
+ mContentResolver.applyBatch(ContactsContract.AUTHORITY, operations);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Problem querying raw_contacts/data", e);
+ } catch (OperationApplicationException e) {
+ if (allowInsert) {
+ // they deleted the photo between insert and update, so insert one
+ insertPhoto(values, rawContactDataUri, false);
+ } else {
+ throw new IllegalStateException("Problem inserting photo raw_contacts/data", e);
+ }
+ }
+ }
}
diff --git a/src/com/android/contacts/ButtonGridLayout.java b/src/com/android/contacts/ButtonGridLayout.java
index e3431b1..6ce3e71 100644
--- a/src/com/android/contacts/ButtonGridLayout.java
+++ b/src/com/android/contacts/ButtonGridLayout.java
@@ -18,14 +18,46 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.view.View.MeasureSpec;
import android.view.View;
import android.view.ViewGroup;
-import android.view.View.MeasureSpec;
+/**
+ * Create a 4x3 grid of dial buttons.
+ *
+ * It was easier and more efficient to do it this way than use
+ * standard layouts. It's perfectly fine (and actually encouraged) to
+ * use custom layouts rather than piling up standard layouts.
+ *
+ * The horizontal and vertical spacings between buttons are controlled
+ * by the amount of padding (attributes on the ButtonGridLayout element):
+ * - horizontal = left + right padding and
+ * - vertical = top + bottom padding.
+ *
+ * This class assumes that all the buttons have the same size.
+ * The buttons will be bottom aligned in their view on layout.
+ *
+ * Invocation: onMeasure is called first by the framework to know our
+ * size. Then onLayout is invoked to layout the buttons.
+ */
+// TODO: Blindly layout the buttons w/o checking if we overrun the
+// bottom-right corner.
public class ButtonGridLayout extends ViewGroup {
+ private final int COLUMNS = 3;
+ private final int ROWS = 4;
- private final int mColumns = 3;
-
+ // Width and height of a button
+ private int mButtonWidth;
+ private int mButtonHeight;
+
+ // Width and height of a button + padding.
+ private int mWidthInc;
+ private int mHeightInc;
+
+ // Height of the dialpad. Used to align it at the bottom of the
+ // view.
+ private int mHeight;
+
public ButtonGridLayout(Context context) {
super(context);
}
@@ -37,61 +69,47 @@
public ButtonGridLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
-
+
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int y = mPaddingTop;
- final int rows = getRows();
- final View child0 = getChildAt(0);
- final int yInc = (getHeight() - mPaddingTop - mPaddingBottom) / rows;
- final int xInc = (getWidth() - mPaddingLeft - mPaddingRight) / mColumns;
- final int childWidth = child0.getMeasuredWidth();
- final int childHeight = child0.getMeasuredHeight();
- final int xOffset = (xInc - childWidth) / 2;
- final int yOffset = (yInc - childHeight) / 2;
-
- for (int row = 0; row < rows; row++) {
+ int i = 0;
+ // The last row is bottom aligned.
+ int y = (b - t) - mHeight + mPaddingTop;
+ for (int row = 0; row < ROWS; row++) {
int x = mPaddingLeft;
- for (int col = 0; col < mColumns; col++) {
- int cell = row * mColumns + col;
- if (cell >= getChildCount()) {
- break;
- }
- View child = getChildAt(cell);
- child.layout(x + xOffset, y + yOffset,
- x + xOffset + childWidth,
- y + yOffset + childHeight);
- x += xInc;
- }
- y += yInc;
- }
- }
+ for (int col = 0; col < COLUMNS; col++) {
+ View child = getChildAt(i);
- private int getRows() {
- return (getChildCount() + mColumns - 1) / mColumns;
- }
-
+ child.layout(x, y, x + mButtonWidth, y + mButtonHeight);
+
+ x += mWidthInc;
+ i++;
+ }
+ y += mHeightInc;
+ }
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = mPaddingLeft + mPaddingRight;
- int height = mPaddingTop + mPaddingBottom;
-
// Measure the first child and get it's size
View child = getChildAt(0);
child.measure(MeasureSpec.UNSPECIFIED , MeasureSpec.UNSPECIFIED);
- int childWidth = child.getMeasuredWidth();
- int childHeight = child.getMeasuredHeight();
+
// Make sure the other children are measured as well, to initialize
for (int i = 1; i < getChildCount(); i++) {
- getChildAt(0).measure(MeasureSpec.UNSPECIFIED , MeasureSpec.UNSPECIFIED);
+ getChildAt(i).measure(MeasureSpec.UNSPECIFIED , MeasureSpec.UNSPECIFIED);
}
- // All cells are going to be the size of the first child
- width += mColumns * childWidth;
- height += getRows() * childHeight;
-
- width = resolveSize(width, widthMeasureSpec);
- height = resolveSize(height, heightMeasureSpec);
+
+ // Store these to be reused in onLayout.
+ mButtonWidth = child.getMeasuredWidth();
+ mButtonHeight = child.getMeasuredHeight();
+ mWidthInc = mButtonWidth + mPaddingLeft + mPaddingRight;
+ mHeightInc = mButtonHeight + mPaddingTop + mPaddingBottom;
+ mHeight = ROWS * mHeightInc;
+
+ final int width = resolveSize(COLUMNS * mWidthInc, widthMeasureSpec);
+ final int height = resolveSize(mHeight, heightMeasureSpec);
+
setMeasuredDimension(width, height);
}
-
}
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index d7d888c..b2baa2c 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -28,10 +28,10 @@
import android.net.Uri;
import android.os.Bundle;
import android.provider.CallLog;
-import android.provider.Contacts;
import android.provider.CallLog.Calls;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.Contacts.Intents.Insert;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
@@ -63,28 +63,28 @@
private TextView mCallDuration;
private String mNumber = null;
-
+
/* package */ LayoutInflater mInflater;
/* package */ Resources mResources;
-
+
static final String[] CALL_LOG_PROJECTION = new String[] {
CallLog.Calls.DATE,
CallLog.Calls.DURATION,
CallLog.Calls.NUMBER,
CallLog.Calls.TYPE,
};
-
+
static final int DATE_COLUMN_INDEX = 0;
static final int DURATION_COLUMN_INDEX = 1;
static final int NUMBER_COLUMN_INDEX = 2;
static final int CALL_TYPE_COLUMN_INDEX = 3;
-
+
static final String[] PHONES_PROJECTION = new String[] {
- Phones.PERSON_ID,
- Phones.DISPLAY_NAME,
- Phones.TYPE,
- Phones.LABEL,
- Phones.NUMBER,
+ PhoneLookup._ID,
+ PhoneLookup.DISPLAY_NAME,
+ PhoneLookup.TYPE,
+ PhoneLookup.LABEL,
+ PhoneLookup.NUMBER,
};
static final int COLUMN_INDEX_ID = 0;
static final int COLUMN_INDEX_NAME = 1;
@@ -100,15 +100,15 @@
mInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
mResources = getResources();
-
+
mCallType = (TextView) findViewById(R.id.type);
mCallTypeIcon = (ImageView) findViewById(R.id.icon);
mCallTime = (TextView) findViewById(R.id.time);
mCallDuration = (TextView) findViewById(R.id.duration);
-
+
getListView().setOnItemClickListener(this);
}
-
+
@Override
public void onResume() {
super.onResume();
@@ -130,13 +130,13 @@
}
}
}
-
+
return super.onKeyDown(keyCode, event);
}
-
+
/**
* Update user interface with details of given call.
- *
+ *
* @param callUri Uri into {@link CallLog.Calls}
*/
private void updateData(Uri callUri) {
@@ -149,13 +149,13 @@
long date = callCursor.getLong(DATE_COLUMN_INDEX);
long duration = callCursor.getLong(DURATION_COLUMN_INDEX);
int callType = callCursor.getInt(CALL_TYPE_COLUMN_INDEX);
-
+
// Pull out string in format [relative], [date]
CharSequence dateClause = DateUtils.formatDateRange(this, date, date,
DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR);
mCallTime.setText(dateClause);
-
+
// Set the duration
if (callType == Calls.MISSED_TYPE) {
mCallDuration.setVisibility(View.GONE);
@@ -163,7 +163,7 @@
mCallDuration.setVisibility(View.VISIBLE);
mCallDuration.setText(formatDuration(duration));
}
-
+
// Set the call type icon and caption
String callText = null;
switch (callType) {
@@ -172,43 +172,44 @@
mCallType.setText(R.string.type_incoming);
callText = getString(R.string.callBack);
break;
-
+
case Calls.OUTGOING_TYPE:
mCallTypeIcon.setImageResource(R.drawable.ic_call_log_header_outgoing_call);
mCallType.setText(R.string.type_outgoing);
callText = getString(R.string.callAgain);
break;
-
+
case Calls.MISSED_TYPE:
mCallTypeIcon.setImageResource(R.drawable.ic_call_log_header_missed_call);
mCallType.setText(R.string.type_missed);
callText = getString(R.string.returnCall);
break;
}
-
+
if (mNumber.equals(CallerInfo.UNKNOWN_NUMBER) ||
mNumber.equals(CallerInfo.PRIVATE_NUMBER)) {
// List is empty, let the empty view show instead.
TextView emptyText = (TextView) findViewById(R.id.emptyText);
if (emptyText != null) {
- emptyText.setText(mNumber.equals(CallerInfo.PRIVATE_NUMBER)
+ emptyText.setText(mNumber.equals(CallerInfo.PRIVATE_NUMBER)
? R.string.private_num : R.string.unknown);
}
} else {
// Perform a reverse-phonebook lookup to find the PERSON_ID
String callLabel = null;
Uri personUri = null;
- Uri phoneUri = Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, Uri.encode(mNumber));
+ Uri phoneUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(mNumber));
Cursor phonesCursor = resolver.query(phoneUri, PHONES_PROJECTION, null, null, null);
try {
if (phonesCursor != null && phonesCursor.moveToFirst()) {
long personId = phonesCursor.getLong(COLUMN_INDEX_ID);
personUri = ContentUris.withAppendedId(
- Contacts.People.CONTENT_URI, personId);
+ Contacts.CONTENT_URI, personId);
callText = getString(R.string.recentCalls_callNumber,
phonesCursor.getString(COLUMN_INDEX_NAME));
mNumber = phonesCursor.getString(COLUMN_INDEX_NUMBER);
- callLabel = Phones.getDisplayLabel(this,
+ callLabel = Phone.getDisplayLabel(this,
phonesCursor.getInt(COLUMN_INDEX_TYPE),
phonesCursor.getString(COLUMN_INDEX_LABEL)).toString();
} else {
@@ -217,10 +218,10 @@
} finally {
if (phonesCursor != null) phonesCursor.close();
}
-
+
// Build list of various available actions
List<ViewEntry> actions = new ArrayList<ViewEntry>();
-
+
Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
Uri.fromParts("tel", mNumber, null));
ViewEntry entry = new ViewEntry(android.R.drawable.sym_action_call, callText,
@@ -228,12 +229,12 @@
entry.number = mNumber;
entry.label = callLabel;
actions.add(entry);
-
+
Intent smsIntent = new Intent(Intent.ACTION_SENDTO,
Uri.fromParts("sms", mNumber, null));
actions.add(new ViewEntry(R.drawable.sym_action_sms,
getString(R.string.menu_sendTextMessage), smsIntent));
-
+
// Let user view contact details if they exist, otherwise add option
// to create new contact from this number.
if (personUri != null) {
@@ -242,12 +243,12 @@
getString(R.string.menu_viewContact), viewIntent));
} else {
Intent createIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
- createIntent.setType(People.CONTENT_ITEM_TYPE);
+ createIntent.setType(Contacts.CONTENT_ITEM_TYPE);
createIntent.putExtra(Insert.PHONE, mNumber);
actions.add(new ViewEntry(R.drawable.sym_action_add,
getString(R.string.recentCalls_addToContact), createIntent));
}
-
+
ViewAdapter adapter = new ViewAdapter(this, actions);
setListAdapter(adapter);
}
@@ -284,7 +285,7 @@
public Intent intent = null;
public String label = null;
public String number = null;
-
+
public ViewEntry(int icon, String text, Intent intent) {
this.icon = icon;
this.text = text;
@@ -293,16 +294,16 @@
}
static final class ViewAdapter extends BaseAdapter {
-
+
private final List<ViewEntry> mActions;
-
+
private final LayoutInflater mInflater;
-
+
public ViewAdapter(Context context, List<ViewEntry> actions) {
mActions = actions;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
-
+
public int getCount() {
return mActions.size();
}
@@ -314,7 +315,7 @@
public long getItemId(int position) {
return position;
}
-
+
public View getView(int position, View convertView, ViewGroup parent) {
// Make sure we have a valid convertView to start with
if (convertView == null) {
@@ -324,7 +325,7 @@
// Fill action with icon and text.
ViewEntry entry = mActions.get(position);
convertView.setTag(entry);
-
+
ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
TextView text = (TextView) convertView.findViewById(android.R.id.text1);
@@ -338,7 +339,7 @@
line2.setVisibility(View.GONE);
} else {
line2.setVisibility(View.VISIBLE);
-
+
TextView label = (TextView) convertView.findViewById(R.id.label);
if (labelEmpty) {
label.setVisibility(View.GONE);
@@ -350,11 +351,11 @@
TextView number = (TextView) convertView.findViewById(R.id.number);
number.setText(entry.number);
}
-
+
return convertView;
}
}
-
+
public void onItemClick(AdapterView parent, View view, int position, long id) {
// Handle passing action off to correct handler.
if (view.getTag() instanceof ViewEntry) {
@@ -363,5 +364,5 @@
startActivity(entry.intent);
}
}
- }
+ }
}
diff --git a/src/com/android/contacts/Collapser.java b/src/com/android/contacts/Collapser.java
new file mode 100644
index 0000000..3872dfd
--- /dev/null
+++ b/src/com/android/contacts/Collapser.java
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+/**
+ * Class used for collapsing data items into groups of similar items. The data items that should be
+ * collapsible should implement the Collapsible interface. The class also contains a utility
+ * function that takes an ArrayList of items and returns a list of the same items collapsed into
+ * groups.
+ */
+public final class Collapser {
+
+ /*
+ * This utility class cannot be instantiated.
+ */
+ private Collapser() {}
+
+ /*
+ * Interface implemented by data types that can be collapsed into groups of similar data. This
+ * can be used for example to collapse similar contact data items into a single item.
+ */
+ public interface Collapsible<T> {
+ public boolean collapseWith(T t);
+ public boolean shouldCollapseWith(T t);
+ }
+
+ /**
+ * Collapses a list of Collapsible items into a list of collapsed items. Items are collapsed
+ * if {@link Collapsible#shouldCollapseWith(Object) return strue, and are collapsed
+ * through the {@Link Collapsible#collapseWith(Object)} function implemented by the data item.
+ *
+ * @param list ArrayList of Objects of type <T extends Collapsible<T>> to be collapsed.
+ */
+ public static <T extends Collapsible<T>> void collapseList(ArrayList<T> list) {
+
+ int listSize = list.size();
+
+ for (int i = 0; i < listSize; i++) {
+ T iItem = list.get(i);
+ if (iItem != null) {
+ for (int j = i + 1; j < listSize; j++) {
+ T jItem = list.get(j);
+ if (jItem != null) {
+ if (iItem.shouldCollapseWith(jItem)) {
+ iItem.collapseWith(jItem);
+ list.set(j, null);
+ }
+ }
+ }
+ }
+ }
+
+ // Remove the null items
+ Iterator<T> itr = list.iterator();
+ while (itr.hasNext()) {
+ if (itr.next() == null) {
+ itr.remove();
+ }
+ }
+
+ }
+}
diff --git a/src/com/android/contacts/ContactEntryAdapter.java b/src/com/android/contacts/ContactEntryAdapter.java
index c5b7ccf..9f11165 100644
--- a/src/com/android/contacts/ContactEntryAdapter.java
+++ b/src/com/android/contacts/ContactEntryAdapter.java
@@ -19,8 +19,8 @@
import android.content.Context;
import android.net.Uri;
import android.os.Parcel;
-import android.provider.Contacts.Organizations;
-import android.provider.Contacts.People;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -31,83 +31,6 @@
public abstract class ContactEntryAdapter<E extends ContactEntryAdapter.Entry>
extends BaseAdapter {
- public static final String[] CONTACT_PROJECTION = new String[] {
- People._ID, // 0
- People.NAME, // 1
- People.NOTES, // 2
- People.PRIMARY_PHONE_ID, // 3
- People.PRESENCE_STATUS, // 4
- People.STARRED, // 5
- People.CUSTOM_RINGTONE, // 6
- People.SEND_TO_VOICEMAIL, // 7
- People.PHONETIC_NAME, // 8
- };
- public static final int CONTACT_ID_COLUMN = 0;
- public static final int CONTACT_NAME_COLUMN = 1;
- public static final int CONTACT_NOTES_COLUMN = 2;
- public static final int CONTACT_PREFERRED_PHONE_COLUMN = 3;
- public static final int CONTACT_SERVER_STATUS_COLUMN = 4;
- public static final int CONTACT_STARRED_COLUMN = 5;
- public static final int CONTACT_CUSTOM_RINGTONE_COLUMN = 6;
- public static final int CONTACT_SEND_TO_VOICEMAIL_COLUMN = 7;
- public static final int CONTACT_PHONETIC_NAME_COLUMN = 8;
-
- public static final String[] PHONES_PROJECTION = new String[] {
- People.Phones._ID, // 0
- People.Phones.NUMBER, // 1
- People.Phones.TYPE, // 2
- People.Phones.LABEL, // 3
- People.Phones.ISPRIMARY, // 4
- };
- public static final int PHONES_ID_COLUMN = 0;
- public static final int PHONES_NUMBER_COLUMN = 1;
- public static final int PHONES_TYPE_COLUMN = 2;
- public static final int PHONES_LABEL_COLUMN = 3;
- public static final int PHONES_ISPRIMARY_COLUMN = 4;
-
- public static final String[] METHODS_PROJECTION = new String[] {
- People.ContactMethods._ID, // 0
- People.ContactMethods.KIND, // 1
- People.ContactMethods.DATA, // 2
- People.ContactMethods.TYPE, // 3
- People.ContactMethods.LABEL, // 4
- People.ContactMethods.ISPRIMARY, // 5
- People.ContactMethods.AUX_DATA, // 6
- };
- public static final String[] METHODS_WITH_PRESENCE_PROJECTION = new String[] {
- People.ContactMethods._ID, // 0
- People.ContactMethods.KIND, // 1
- People.ContactMethods.DATA, // 2
- People.ContactMethods.TYPE, // 3
- People.ContactMethods.LABEL, // 4
- People.ContactMethods.ISPRIMARY, // 5
- People.ContactMethods.AUX_DATA, // 6
- People.PRESENCE_STATUS, // 7
- };
- public static final int METHODS_ID_COLUMN = 0;
- public static final int METHODS_KIND_COLUMN = 1;
- public static final int METHODS_DATA_COLUMN = 2;
- public static final int METHODS_TYPE_COLUMN = 3;
- public static final int METHODS_LABEL_COLUMN = 4;
- public static final int METHODS_ISPRIMARY_COLUMN = 5;
- public static final int METHODS_AUX_DATA_COLUMN = 6;
- public static final int METHODS_STATUS_COLUMN = 7;
-
- public static final String[] ORGANIZATIONS_PROJECTION = new String[] {
- Organizations._ID, // 0
- Organizations.TYPE, // 1
- Organizations.LABEL, // 2
- Organizations.COMPANY, // 3
- Organizations.TITLE, // 4
- Organizations.ISPRIMARY, // 5
- };
- public static final int ORGANIZATIONS_ID_COLUMN = 0;
- public static final int ORGANIZATIONS_TYPE_COLUMN = 1;
- public static final int ORGANIZATIONS_LABEL_COLUMN = 2;
- public static final int ORGANIZATIONS_COMPANY_COLUMN = 3;
- public static final int ORGANIZATIONS_TITLE_COLUMN = 4;
- public static final int ORGANIZATIONS_ISPRIMARY_COLUMN = 5;
-
protected ArrayList<ArrayList<E>> mSections;
protected LayoutInflater mInflater;
protected Context mContext;
@@ -117,42 +40,39 @@
* Base class for adapter entries.
*/
public static class Entry {
- /** Details from the person table */
- public static final int KIND_CONTACT = -1;
- /** Synthesized phone entry that will send an SMS instead of call the number */
- public static final int KIND_SMS = -2;
- /** A section separator */
- public static final int KIND_SEPARATOR = -3;
-
+ public int type = -1;
public String label;
public String data;
public Uri uri;
public long id = 0;
+ public long contactId;
public int maxLines = 1;
- public int kind;
-
+ public String mimetype;
+
/**
* Helper for making subclasses parcelable.
*/
protected void writeToParcel(Parcel p) {
+ p.writeInt(type);
p.writeString(label);
p.writeString(data);
p.writeParcelable(uri, 0);
p.writeLong(id);
p.writeInt(maxLines);
- p.writeInt(kind);
+ p.writeString(mimetype);
}
-
+
/**
* Helper for making subclasses parcelable.
*/
protected void readFromParcel(Parcel p) {
+ type = p.readInt();
label = p.readString();
data = p.readString();
uri = p.readParcelable(null);
id = p.readLong();
maxLines = p.readInt();
- kind = p.readInt();
+ mimetype = p.readString();
}
}
@@ -165,7 +85,7 @@
/**
* Resets the section data.
- *
+ *
* @param sections the section data
*/
public final void setSections(ArrayList<ArrayList<E>> sections, boolean separators) {
@@ -176,7 +96,7 @@
/**
* Resets the section data and returns the position of the given entry.
- *
+ *
* @param sections the section data
* @param entry the entry to return the position for
* @return the position of entry, or -1 if it isn't found
@@ -252,7 +172,7 @@
/**
* Get the entry for the given position.
- *
+ *
* @param sections the list of sections
* @param position the position for the desired entry
* @return the ContactEntry for the given position
@@ -277,7 +197,7 @@
/**
* Get the count of entries in all sections
- *
+ *
* @param sections the list of sections
* @return the count of entries in all sections
*/
@@ -325,7 +245,7 @@
/**
* Create a new view for an entry.
- *
+ *
* @parent the parent ViewGroup
* @return the newly created view
*/
@@ -333,7 +253,7 @@
/**
* Binds the data from an entry to a view.
- *
+ *
* @param view the view to display the entry in
* @param entry the data to bind
*/
diff --git a/src/com/android/contacts/ContactOptionsActivity.java b/src/com/android/contacts/ContactOptionsActivity.java
new file mode 100644
index 0000000..f93ddf8
--- /dev/null
+++ b/src/com/android/contacts/ContactOptionsActivity.java
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import android.app.Activity;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract.Contacts;
+import android.util.Log;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+/**
+ * An activity for selecting options for a given contact: custom ringtone and send-to-voicemail.
+ */
+public class ContactOptionsActivity extends Activity implements View.OnClickListener {
+
+ private static final String TAG = "ContactOptionsActivity";
+
+ private static final String[] AGGREGATES_PROJECTION = new String[] {
+ Contacts.CUSTOM_RINGTONE, Contacts.SEND_TO_VOICEMAIL
+ };
+
+ private static final int COL_CUSTOM_RINGTONE = 0;
+ private static final int COL_SEND_TO_VOICEMAIL = 1;
+
+ /** The launch code when picking a ringtone */
+ private static final int RINGTONE_PICKED = 3023;
+
+ private String mCustomRingtone;
+ private boolean mSendToVoicemail;
+ private TextView mRingtoneTitle;
+ private CheckBox mSendToVoicemailCheckbox;
+
+ private Uri mLookupUri;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mLookupUri = getIntent().getData();
+
+ setContentView(R.layout.contact_options);
+
+ View ringtoneLayout = findViewById(R.id.ringtone);
+ ringtoneLayout.setOnClickListener(this);
+ TextView label = (TextView)findViewById(R.id.label);
+ label.setText(getString(R.string.label_ringtone));
+
+ mRingtoneTitle = (TextView)ringtoneLayout.findViewById(R.id.data);
+
+ View sendToVoicemailLayout = findViewById(R.id.voicemail);
+ sendToVoicemailLayout.setOnClickListener(this);
+ label = (TextView)sendToVoicemailLayout.findViewById(R.id.label);
+ label.setText(getString(R.string.actionIncomingCall));
+
+ mSendToVoicemailCheckbox = (CheckBox)sendToVoicemailLayout.findViewById(R.id.checkbox);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (!loadData()) {
+ finish();
+ }
+
+ updateView();
+ }
+
+ private void updateView() {
+ if (mCustomRingtone == null) {
+ mRingtoneTitle.setText(getString(R.string.default_ringtone));
+ } else {
+ Uri ringtoneUri = Uri.parse(mCustomRingtone);
+ Ringtone ringtone = RingtoneManager.getRingtone(this, ringtoneUri);
+ if (ringtone == null) {
+ Log.w(TAG, "ringtone's URI doesn't resolve to a Ringtone");
+ return;
+ }
+ mRingtoneTitle.setText(ringtone.getTitle(this));
+ }
+
+ mSendToVoicemailCheckbox.setChecked(mSendToVoicemail);
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.ringtone: {
+ doPickRingtone();
+ break;
+ }
+ case R.id.voicemail: {
+ doToggleSendToVoicemail();
+ break;
+ }
+ }
+ }
+
+ private void doPickRingtone() {
+
+ Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
+ // Allow user to pick 'Default'
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
+ // Show only ringtones
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE);
+ // Don't show 'Silent'
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false);
+
+ Uri ringtoneUri;
+ if (mCustomRingtone != null) {
+ ringtoneUri = Uri.parse(mCustomRingtone);
+ } else {
+ // Otherwise pick default ringtone Uri so that something is selected.
+ ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
+ }
+
+ // Put checkmark next to the current ringtone for this contact
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, ringtoneUri);
+
+ // Launch!
+ startActivityForResult(intent, RINGTONE_PICKED);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode != RESULT_OK) {
+ return;
+ }
+
+ switch (requestCode) {
+ case RINGTONE_PICKED: {
+ Uri pickedUri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
+ handleRingtonePicked(pickedUri);
+ break;
+ }
+ }
+ }
+
+ private void handleRingtonePicked(Uri pickedUri) {
+ if (pickedUri == null || RingtoneManager.isDefault(pickedUri)) {
+ mCustomRingtone = null;
+ } else {
+ mCustomRingtone = pickedUri.toString();
+ }
+ saveData();
+ updateView();
+ }
+
+ private void doToggleSendToVoicemail() {
+ mSendToVoicemailCheckbox.toggle();
+ mSendToVoicemail = mSendToVoicemailCheckbox.isChecked();
+ saveData();
+ updateView();
+ }
+
+ private boolean loadData() {
+ Cursor c =
+ getContentResolver().query(mLookupUri, AGGREGATES_PROJECTION, null, null, null);
+ try {
+ if (!c.moveToFirst()) {
+ return false;
+ }
+
+ mCustomRingtone = c.getString(COL_CUSTOM_RINGTONE);
+ mSendToVoicemail = c.getInt(COL_SEND_TO_VOICEMAIL) != 0;
+
+ } finally {
+ c.close();
+ }
+ return true;
+ }
+
+ private void saveData() {
+ ContentValues values = new ContentValues(2);
+ values.put(Contacts.CUSTOM_RINGTONE, mCustomRingtone);
+ values.put(Contacts.SEND_TO_VOICEMAIL, mSendToVoicemail);
+ getContentResolver().update(mLookupUri, values, null, null);
+ }
+}
+
+
diff --git a/src/com/android/contacts/ContactsGroupSyncSelector.java b/src/com/android/contacts/ContactsGroupSyncSelector.java
deleted file mode 100644
index e1fbdf1..0000000
--- a/src/com/android/contacts/ContactsGroupSyncSelector.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts;
-
-import com.google.android.googlelogin.GoogleLoginServiceConstants;
-import com.google.android.googlelogin.GoogleLoginServiceHelper;
-
-import android.app.ListActivity;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.provider.Contacts;
-import android.provider.Gmail;
-import android.provider.Contacts.Groups;
-import android.provider.Contacts.Settings;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-
-import java.util.ArrayList;
-
-public final class ContactsGroupSyncSelector extends ListActivity implements View.OnClickListener {
-
- private static final String[] PROJECTION = new String[] {
- Groups._ID, // 0
- Groups.NAME, // 1
- Groups.SHOULD_SYNC, // 2
- Groups.SYSTEM_ID, // 3
- };
- private static final int COLUMN_INDEX_ID = 0;
- private static final int COLUMN_INDEX_NAME = 1;
- private static final int COLUMN_INDEX_SHOULD_SYNC = 2;
- private static final int COLUMN_INDEX_SYSTEM_ID = 3;
-
- private static final int SUBACTIVITY_GET_ACCOUNT = 1;
-
- ArrayList<Boolean> mChecked;
- ArrayList<Long> mGroupIds;
- boolean mSyncAllGroups;
-
- private final class GroupsAdapter extends ArrayAdapter<CharSequence> {
- public GroupsAdapter(ArrayList<CharSequence> items) {
- super(ContactsGroupSyncSelector.this,
- android.R.layout.simple_list_item_checked,
- android.R.id.text1, items);
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- return mSyncAllGroups;
- }
-
- @Override
- public boolean isEnabled(int pos) {
- if (mSyncAllGroups && pos != 0) {
- return false;
- } else {
- return true;
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = super.getView(position, convertView, parent);
- if (mSyncAllGroups && position != 0) {
- v.setEnabled(false);
- } else {
- v.setEnabled(true);
- }
- return v;
- }
- }
-
- /**
- * Handles clicks on the list items
- */
- @Override
- protected void onListItemClick(ListView list, View view, int position, long id) {
- boolean isChecked = list.isItemChecked(position);
- mChecked.set(position, isChecked);
- if (position == 0) {
- mSyncAllGroups = isChecked;
- adjustChecks();
- }
- }
-
- /**
- * Handles clicks on the OK and cancel buttons
- */
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.cancel: {
- finish();
- break;
- }
-
- case R.id.ok: {
- // The list isn't setup yet, so just return without doing anything.
- if (mChecked == null) {
- finish();
- return;
- }
-
- final ContentResolver resolver = getContentResolver();
- if (mSyncAllGroups) {
- // For now we only support a single account and the UI doesn't know what
- // the account name is, so we're using a global setting for SYNC_EVERYTHING.
- // Some day when we add multiple accounts to the UI this should use the per
- // account setting.
- Settings.setSetting(resolver, null, Settings.SYNC_EVERYTHING, "1");
- } else {
- ContentValues values = new ContentValues();
- int count = mChecked.size();
- for (int i = 1; i < count; i++) {
- values.clear();
- values.put(Groups.SHOULD_SYNC, mChecked.get(i));
- resolver.update(
- ContentUris.withAppendedId(Groups.CONTENT_URI, mGroupIds.get(i)),
- values, null, null);
- }
- // For now we only support a single account and the UI doesn't know what
- // the account name is, so we're using a global setting for SYNC_EVERYTHING.
- // Some day when we add multiple accounts to the UI this should use the per
- // account setting.
- Settings.setSetting(resolver, null, Settings.SYNC_EVERYTHING, "0");
- }
- finish();
- break;
- }
- }
- }
-
- @Override
- protected void onCreate(Bundle savedState) {
- super.onCreate(savedState);
-
- // Only look for an account on first run.
- if (savedState == null) {
- // This will request a Gmail account and if none are present, it will
- // invoke SetupWizard to login or create one. The result is returned
- // through onActivityResult().
- Bundle bundle = new Bundle();
- bundle.putCharSequence("optional_message", getText(R.string.contactsSyncPlug));
- GoogleLoginServiceHelper.getCredentials(this, SUBACTIVITY_GET_ACCOUNT,
- bundle, GoogleLoginServiceConstants.PREFER_HOSTED, Gmail.GMAIL_AUTH_SERVICE,
- true);
- }
-
- setContentView(R.layout.sync_settings);
-
- findViewById(R.id.ok).setOnClickListener(this);
- findViewById(R.id.cancel).setOnClickListener(this);
-
- getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
- super.onActivityResult(requestCode, resultCode, intent);
- if (requestCode == SUBACTIVITY_GET_ACCOUNT) {
- if (resultCode == RESULT_OK) {
- // There is an account setup, build the group list
- buildItems();
- adjustChecks();
- } else {
- finish();
- }
- }
- }
-
- private void buildItems() {
- final ContentResolver resolver = getContentResolver();
- Cursor cursor = resolver.query(Groups.CONTENT_URI, PROJECTION, null, null, Groups.NAME);
- if (cursor != null) {
- try {
- int count = cursor.getCount() + 1; // add 1 for "sync all"
- ArrayList<CharSequence> items = new ArrayList<CharSequence>(count);
- ArrayList<Boolean> checked = new ArrayList<Boolean>(count);
- ArrayList<Long> groupIds = new ArrayList<Long>(count);
-
- // The first item in the list is always "sync all"
- items.add(getString(R.string.syncAllGroups));
- checked.add(mSyncAllGroups);
- groupIds.add(Long.valueOf(0)); // dummy entry
-
- while (cursor.moveToNext()) {
- String name = cursor.getString(COLUMN_INDEX_NAME);
- String systemId = cursor.isNull(COLUMN_INDEX_SYSTEM_ID) ?
- null : cursor.getString(COLUMN_INDEX_SYSTEM_ID);
- if (systemId == null || !Groups.GROUP_MY_CONTACTS.equals(systemId)) {
- // Localize the "Starred in Android" string which we get from the server
- // side.
- if (Groups.GROUP_ANDROID_STARRED.equals(name)) {
- name = getString(R.string.starredInAndroid);
- }
- items.add(name);
- checked.add(cursor.getInt(COLUMN_INDEX_SHOULD_SYNC) != 0);
- groupIds.add(cursor.getLong(COLUMN_INDEX_ID));
- } else {
- // If My Contacts is around it wants to be the second list entry
- items.add(1, getString(R.string.groupNameMyContacts));
- checked.add(1, cursor.getInt(COLUMN_INDEX_SHOULD_SYNC) != 0);
- groupIds.add(1, cursor.getLong(COLUMN_INDEX_ID));
- }
- }
- mChecked = checked;
- mGroupIds = groupIds;
- mSyncAllGroups = getShouldSyncEverything(resolver);
-
- // Setup the adapter
- setListAdapter(new GroupsAdapter(items));
- } finally {
- cursor.close();
- }
- }
- }
-
- private void adjustChecks() {
- final ListView list = getListView();
- if (mSyncAllGroups) {
- int count = list.getCount();
- for (int i = 0; i < count; i++) {
- list.setItemChecked(i, true);
- }
- } else {
- ArrayList<Boolean> checked = mChecked;
- int count = list.getCount();
- for (int i = 0; i < count; i++) {
- list.setItemChecked(i, checked.get(i));
- }
- }
- }
-
- private static boolean getShouldSyncEverything(ContentResolver cr) {
- // For now we only support a single account and the UI doesn't know what
- // the account name is, so we're using a global setting for SYNC_EVERYTHING.
- // Some day when we add multiple accounts to the UI this should use the per
- // account setting.
- String value = Contacts.Settings.getSetting(cr, null, Contacts.Settings.SYNC_EVERYTHING);
- if (value == null) {
- // If nothing is set yet we default to syncing everything
- return true;
- }
- return !TextUtils.isEmpty(value) && !"0".equals(value);
- }
-}
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 02c70d2..5613794 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -16,8 +16,17 @@
package com.android.contacts;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.Sources;
+import com.android.contacts.ui.DisplayGroupsActivity;
+import com.android.contacts.ui.DisplayGroupsActivity.Prefs;
+import com.android.contacts.util.AccountSelectionUtil;
+import com.android.contacts.util.Constants;
+
+import android.accounts.Account;
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.app.ListActivity;
import android.app.SearchManager;
import android.content.AsyncQueryHandler;
@@ -26,13 +35,13 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.IContentProvider;
-import android.content.ISyncAdapter;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.UriMatcher;
import android.content.res.Resources;
import android.database.CharArrayBuffer;
import android.database.Cursor;
+import android.database.MatrixCursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -42,59 +51,92 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.net.Uri.Builder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Message;
import android.os.Parcelable;
-import android.os.RemoteException;
import android.preference.PreferenceManager;
-import android.provider.Contacts;
+import android.provider.ContactsContract;
+import android.provider.Settings;
import android.provider.Contacts.ContactMethods;
-import android.provider.Contacts.Groups;
-import android.provider.Contacts.Intents;
import android.provider.Contacts.People;
+import android.provider.Contacts.PeopleColumns;
import android.provider.Contacts.Phones;
-import android.provider.Contacts.Presence;
-import android.provider.Contacts.Intents.Insert;
-import android.provider.Contacts.Intents.UI;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.Presence;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.Contacts.AggregationSuggestions;
+import android.provider.ContactsContract.Intents.Insert;
+import android.provider.ContactsContract.Intents.UI;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.SparseArray;
import android.view.ContextMenu;
+import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.inputmethod.InputMethodManager;
+import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AlphabetIndexer;
+import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.ImageView;
import android.widget.ListView;
+import android.widget.QuickContactBadge;
import android.widget.ResourceCursorAdapter;
import android.widget.SectionIndexer;
import android.widget.TextView;
+import android.widget.AbsListView.OnScrollListener;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Locale;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/*TODO(emillar) I commented most of the code that deals with modes and filtering. It should be
+ * brought back in as we add back that functionality.
+ */
+
/**
* Displays a list of contacts. Usually is embedded into the ContactsActivity.
*/
-public final class ContactsListActivity extends ListActivity
- implements View.OnCreateContextMenuListener, DialogInterface.OnClickListener {
+@SuppressWarnings("deprecation")
+public class ContactsListActivity extends ListActivity implements
+ View.OnCreateContextMenuListener, View.OnClickListener {
+
+ public static class JoinContactActivity extends ContactsListActivity {
+
+ }
+
private static final String TAG = "ContactsListActivity";
- private static final boolean ENABLE_ACTION_ICON_OVERLAYS = false;
+ private static final boolean ENABLE_ACTION_ICON_OVERLAYS = true;
private static final String LIST_STATE_KEY = "liststate";
private static final String FOCUS_KEY = "focused";
-
+
static final int MENU_ITEM_VIEW_CONTACT = 1;
static final int MENU_ITEM_CALL = 2;
static final int MENU_ITEM_EDIT_BEFORE_CALL = 3;
@@ -104,15 +146,39 @@
static final int MENU_ITEM_DELETE = 7;
static final int MENU_ITEM_TOGGLE_STAR = 8;
- public static final int MENU_SEARCH = 1;
- public static final int MENU_DIALER = 9;
- public static final int MENU_NEW_CONTACT = 10;
- public static final int MENU_DISPLAY_GROUP = 11;
- public static final int MENU_IMPORT_CONTACTS = 12;
- public static final int MENU_EXPORT_CONTACTS = 13;
-
private static final int SUBACTIVITY_NEW_CONTACT = 1;
-
+ private static final int SUBACTIVITY_VIEW_CONTACT = 2;
+ private static final int SUBACTIVITY_DISPLAY_GROUP = 3;
+
+ /**
+ * The action for the join contact activity.
+ * <p>
+ * Input: extra field {@link #EXTRA_AGGREGATE_ID} is the aggregate ID.
+ *
+ * TODO: move to {@link ContactsContract}.
+ */
+ public static final String JOIN_AGGREGATE =
+ "com.android.contacts.action.JOIN_AGGREGATE";
+
+ /**
+ * Used with {@link #JOIN_AGGREGATE} to give it the target for aggregation.
+ * <p>
+ * Type: LONG
+ */
+ public static final String EXTRA_AGGREGATE_ID =
+ "com.android.contacts.action.AGGREGATE_ID";
+
+ /**
+ * Used with {@link #JOIN_AGGREGATE} to give it the name of the aggregation target.
+ * <p>
+ * Type: STRING
+ */
+ @Deprecated
+ public static final String EXTRA_AGGREGATE_NAME =
+ "com.android.contacts.action.AGGREGATE_NAME";
+
+ public static final String AUTHORITIES_FILTER_KEY = "authorities";
+
/** Mask for picker mode */
static final int MODE_MASK_PICKER = 0x80000000;
/** Mask for no presence mode */
@@ -123,177 +189,175 @@
static final int MODE_MASK_CREATE_NEW = 0x10000000;
/** Mask for showing photos in the list */
static final int MODE_MASK_SHOW_PHOTOS = 0x08000000;
+ /** Mask for hiding additional information e.g. primary phone number in the list */
+ static final int MODE_MASK_NO_DATA = 0x04000000;
+ /** Mask for showing a call button in the list */
+ static final int MODE_MASK_SHOW_CALL_BUTTON = 0x02000000;
+ /** Mask to disable quickcontact (images will show as normal images) */
+ static final int MODE_MASK_DISABLE_QUIKCCONTACT = 0x01000000;
+ /** Mask to show the total number of contacts at the top */
+ static final int MODE_MASK_SHOW_NUMBER_OF_CONTACTS = 0x00800000;
/** Unknown mode */
static final int MODE_UNKNOWN = 0;
- /** Show members of the "Contacts" group */
- static final int MODE_GROUP = 5;
- /** Show all contacts sorted alphabetically */
- static final int MODE_ALL_CONTACTS = 10;
- /** Show all contacts with phone numbers, sorted alphabetically */
- static final int MODE_WITH_PHONES = 15;
+ /** Default mode */
+ static final int MODE_DEFAULT = 4 | MODE_MASK_SHOW_PHOTOS | MODE_MASK_SHOW_NUMBER_OF_CONTACTS;
+ /** Custom mode */
+ static final int MODE_CUSTOM = 8;
/** Show all starred contacts */
- static final int MODE_STARRED = 20;
+ static final int MODE_STARRED = 20 | MODE_MASK_SHOW_PHOTOS;
/** Show frequently contacted contacts */
- static final int MODE_FREQUENT = 30;
+ static final int MODE_FREQUENT = 30 | MODE_MASK_SHOW_PHOTOS;
/** Show starred and the frequent */
- static final int MODE_STREQUENT = 35 | MODE_MASK_SHOW_PHOTOS;
+ static final int MODE_STREQUENT = 35 | MODE_MASK_SHOW_PHOTOS | MODE_MASK_SHOW_CALL_BUTTON;
/** Show all contacts and pick them when clicking */
- static final int MODE_PICK_CONTACT = 40 | MODE_MASK_PICKER;
+ static final int MODE_PICK_CONTACT = 40 | MODE_MASK_PICKER | MODE_MASK_SHOW_PHOTOS
+ | MODE_MASK_DISABLE_QUIKCCONTACT;
/** Show all contacts as well as the option to create a new one */
- static final int MODE_PICK_OR_CREATE_CONTACT = 42 | MODE_MASK_PICKER | MODE_MASK_CREATE_NEW;
+ static final int MODE_PICK_OR_CREATE_CONTACT = 42 | MODE_MASK_PICKER | MODE_MASK_CREATE_NEW
+ | MODE_MASK_SHOW_PHOTOS | MODE_MASK_DISABLE_QUIKCCONTACT;
+ /** Show all people through the legacy provider and pick them when clicking */
+ static final int MODE_LEGACY_PICK_PERSON = 43 | MODE_MASK_PICKER | MODE_MASK_SHOW_PHOTOS
+ | MODE_MASK_DISABLE_QUIKCCONTACT;
+ /** Show all people through the legacy provider as well as the option to create a new one */
+ static final int MODE_LEGACY_PICK_OR_CREATE_PERSON = 44 | MODE_MASK_PICKER
+ | MODE_MASK_CREATE_NEW | MODE_MASK_SHOW_PHOTOS | MODE_MASK_DISABLE_QUIKCCONTACT;
/** Show all contacts and pick them when clicking, and allow creating a new contact */
static final int MODE_INSERT_OR_EDIT_CONTACT = 45 | MODE_MASK_PICKER | MODE_MASK_CREATE_NEW;
/** Show all phone numbers and pick them when clicking */
static final int MODE_PICK_PHONE = 50 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE;
+ /** Show all phone numbers through the legacy provider and pick them when clicking */
+ static final int MODE_LEGACY_PICK_PHONE =
+ 51 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE | MODE_MASK_NO_FILTER;
/** Show all postal addresses and pick them when clicking */
static final int MODE_PICK_POSTAL =
55 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE | MODE_MASK_NO_FILTER;
+ /** Show all postal addresses and pick them when clicking */
+ static final int MODE_LEGACY_PICK_POSTAL =
+ 56 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE | MODE_MASK_NO_FILTER;
+ static final int MODE_GROUP = 57 | MODE_MASK_SHOW_PHOTOS;
/** Run a search query */
- static final int MODE_QUERY = 60 | MODE_MASK_NO_FILTER;
+ static final int MODE_QUERY = 60 | MODE_MASK_NO_FILTER | MODE_MASK_SHOW_NUMBER_OF_CONTACTS;
/** Run a search query in PICK mode, but that still launches to VIEW */
static final int MODE_QUERY_PICK_TO_VIEW = 65 | MODE_MASK_NO_FILTER | MODE_MASK_PICKER;
- static final int DEFAULT_MODE = MODE_ALL_CONTACTS;
+ /** Show join suggestions followed by an A-Z list */
+ static final int MODE_JOIN_CONTACT = 70 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE
+ | MODE_MASK_NO_DATA | MODE_MASK_SHOW_PHOTOS | MODE_MASK_DISABLE_QUIKCCONTACT;
- /**
- * The type of data to display in the main contacts list.
- */
- static final String PREF_DISPLAY_TYPE = "display_system_group";
+ /** Maximum number of suggestions shown for joining aggregates */
+ static final int MAX_SUGGESTIONS = 4;
- /** Unknown display type. */
- static final int DISPLAY_TYPE_UNKNOWN = -1;
- /** Display all contacts */
- static final int DISPLAY_TYPE_ALL = 0;
- /** Display all contacts that have phone numbers */
- static final int DISPLAY_TYPE_ALL_WITH_PHONES = 1;
- /** Display a system group */
- static final int DISPLAY_TYPE_SYSTEM_GROUP = 2;
- /** Display a user group */
- static final int DISPLAY_TYPE_USER_GROUP = 3;
+ static final String NAME_COLUMN = Contacts.DISPLAY_NAME;
+ //static final String SORT_STRING = People.SORT_STRING;
- /**
- * Info about what to display. If {@link #PREF_DISPLAY_TYPE}
- * is {@link #DISPLAY_TYPE_SYSTEM_GROUP} then this will be the system id.
- * If {@link #PREF_DISPLAY_TYPE} is {@link #DISPLAY_TYPE_USER_GROUP} then this will
- * be the group name.
- */
- static final String PREF_DISPLAY_INFO = "display_group";
-
-
- static final String NAME_COLUMN = People.DISPLAY_NAME;
- static final String SORT_STRING = People.SORT_STRING;
-
- static final String[] CONTACTS_PROJECTION = new String[] {
- People._ID, // 0
- NAME_COLUMN, // 1
- People.NUMBER, // 2
- People.TYPE, // 3
- People.LABEL, // 4
- People.STARRED, // 5
- People.PRIMARY_PHONE_ID, // 6
- People.PRIMARY_EMAIL_ID, // 7
- People.PRESENCE_STATUS, // 8
- SORT_STRING, // 9
+ static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME, // 1
+ Contacts.STARRED, //2
+ Contacts.TIMES_CONTACTED, //3
+ Contacts.CONTACT_PRESENCE, //4
+ Contacts.PHOTO_ID, //5
+ Contacts.LOOKUP_KEY, //6
+ Contacts.HAS_PHONE_NUMBER, //7
};
-
- static final String[] SIMPLE_CONTACTS_PROJECTION = new String[] {
- People._ID, // 0
- NAME_COLUMN, // 1
+ static final String[] CONTACTS_SUMMARY_PROJECTION_FROM_EMAIL = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME, // 1
+ Contacts.STARRED, //2
+ Contacts.TIMES_CONTACTED, //3
+ Contacts.CONTACT_PRESENCE, //4
+ Contacts.PHOTO_ID, //5
+ Contacts.LOOKUP_KEY, //6
+ // email lookup doesn't included HAS_PHONE_NUMBER OR LOOKUP_KEY in projection
};
-
- static final String[] STREQUENT_PROJECTION = new String[] {
+ static final String[] LEGACY_PEOPLE_PROJECTION = new String[] {
People._ID, // 0
- NAME_COLUMN, // 1
- People.NUMBER, // 2
- People.TYPE, // 3
- People.LABEL, // 4
- People.STARRED, // 5
- People.PRIMARY_PHONE_ID, // 6
- People.PRIMARY_EMAIL_ID, // 7
- People.PRESENCE_STATUS, // 8
- "photo_data", // 9
- People.TIMES_CONTACTED, // 10 (not displayed, but required for the order by to work)
+ People.DISPLAY_NAME, // 1
+ People.STARRED, //2
+ PeopleColumns.TIMES_CONTACTED, //3
+ People.PRESENCE_STATUS, //4
};
+ static final int SUMMARY_ID_COLUMN_INDEX = 0;
+ static final int SUMMARY_NAME_COLUMN_INDEX = 1;
+ static final int SUMMARY_STARRED_COLUMN_INDEX = 2;
+ static final int SUMMARY_TIMES_CONTACTED_COLUMN_INDEX = 3;
+ static final int SUMMARY_PRESENCE_STATUS_COLUMN_INDEX = 4;
+ static final int SUMMARY_PHOTO_ID_COLUMN_INDEX = 5;
+ static final int SUMMARY_LOOKUP_KEY = 6;
+ static final int SUMMARY_HAS_PHONE_COLUMN_INDEX = 7;
static final String[] PHONES_PROJECTION = new String[] {
- Phones._ID, // 0
- NAME_COLUMN, // 1
- Phones.NUMBER, // 2
- Phones.TYPE, // 3
- Phones.LABEL, // 4
- Phones.STARRED, // 5
- Phones.PERSON_ID, // 6
+ Phone._ID, //0
+ Phone.TYPE, //1
+ Phone.LABEL, //2
+ Phone.NUMBER, //3
+ Phone.DISPLAY_NAME, // 4
+ Phone.CONTACT_ID, // 5
+ };
+ static final String[] LEGACY_PHONES_PROJECTION = new String[] {
+ Phones._ID, //0
+ Phones.TYPE, //1
+ Phones.LABEL, //2
+ Phones.NUMBER, //3
+ People.DISPLAY_NAME, // 4
+ };
+ static final int PHONE_ID_COLUMN_INDEX = 0;
+ static final int PHONE_TYPE_COLUMN_INDEX = 1;
+ static final int PHONE_LABEL_COLUMN_INDEX = 2;
+ static final int PHONE_NUMBER_COLUMN_INDEX = 3;
+ static final int PHONE_DISPLAY_NAME_COLUMN_INDEX = 4;
+ static final int PHONE_CONTACT_ID_COLUMN_INDEX = 5;
+
+ static final String[] POSTALS_PROJECTION = new String[] {
+ StructuredPostal._ID, //0
+ StructuredPostal.TYPE, //1
+ StructuredPostal.LABEL, //2
+ StructuredPostal.DATA, //3
+ StructuredPostal.DISPLAY_NAME, // 4
+ };
+ static final String[] LEGACY_POSTALS_PROJECTION = new String[] {
+ ContactMethods._ID, //0
+ ContactMethods.TYPE, //1
+ ContactMethods.LABEL, //2
+ ContactMethods.DATA, //3
+ People.DISPLAY_NAME, // 4
+ };
+ static final String[] RAW_CONTACTS_PROJECTION = new String[] {
+ RawContacts._ID, //0
+ RawContacts.CONTACT_ID, //1
+ RawContacts.ACCOUNT_TYPE, //2
};
- static final String[] CONTACT_METHODS_PROJECTION = new String[] {
- ContactMethods._ID, // 0
- NAME_COLUMN, // 1
- ContactMethods.DATA, // 2
- ContactMethods.TYPE, // 3
- ContactMethods.LABEL, // 4
- ContactMethods.STARRED, // 5
- ContactMethods.PERSON_ID, // 6
- };
-
- static final int ID_COLUMN_INDEX = 0;
- static final int NAME_COLUMN_INDEX = 1;
- static final int NUMBER_COLUMN_INDEX = 2;
- static final int DATA_COLUMN_INDEX = 2;
- static final int TYPE_COLUMN_INDEX = 3;
- static final int LABEL_COLUMN_INDEX = 4;
- static final int STARRED_COLUMN_INDEX = 5;
- static final int PRIMARY_PHONE_ID_COLUMN_INDEX = 6;
- static final int PRIMARY_EMAIL_ID_COLUMN_INDEX = 7;
- static final int SERVER_STATUS_COLUMN_INDEX = 8;
- static final int PHOTO_COLUMN_INDEX = 9;
- static final int SORT_STRING_INDEX = 9;
-
- static final int PHONES_PERSON_ID_INDEX = 6;
- static final int SIMPLE_CONTACTS_PERSON_ID_INDEX = 0;
-
- static final int DISPLAY_GROUP_INDEX_ALL_CONTACTS = 0;
- static final int DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES = 1;
- static final int DISPLAY_GROUP_INDEX_MY_CONTACTS = 2;
+ static final int POSTAL_ID_COLUMN_INDEX = 0;
+ static final int POSTAL_TYPE_COLUMN_INDEX = 1;
+ static final int POSTAL_LABEL_COLUMN_INDEX = 2;
+ static final int POSTAL_ADDRESS_COLUMN_INDEX = 3;
+ static final int POSTAL_DISPLAY_NAME_COLUMN_INDEX = 4;
private static final int QUERY_TOKEN = 42;
- private static final String[] GROUPS_PROJECTION = new String[] {
- Groups.SYSTEM_ID, // 0
- Groups.NAME, // 1
- };
- private static final int GROUPS_COLUMN_INDEX_SYSTEM_ID = 0;
- private static final int GROUPS_COLUMN_INDEX_NAME = 1;
-
- static final String GROUP_WITH_PHONES = "android_smartgroup_phone";
+ static final String KEY_PICKER_MODE = "picker_mode";
- ContactItemListAdapter mAdapter;
+ private ContactItemListAdapter mAdapter;
- int mMode = DEFAULT_MODE;
- // The current display group
- private String mDisplayInfo;
- private int mDisplayType;
- // The current list of display groups, during selection from menu
- private CharSequence[] mDisplayGroups;
- // If true position 2 in mDisplayGroups is the MyContacts group
- private boolean mDisplayGroupsIncludesMyContacts = false;
+ int mMode = MODE_DEFAULT;
- private int mDisplayGroupOriginalSelection;
- private int mDisplayGroupCurrentSelection;
-
private QueryHandler mQueryHandler;
- private String mQuery;
- private Uri mGroupFilterUri;
- private Uri mGroupUri;
private boolean mJustCreated;
private boolean mSyncEnabled;
+ private Uri mSelectedContactUri;
- /**
- * Cursor row index that holds reference back to {@link People#_ID}, such as
- * {@link ContactMethods#PERSON_ID}. Used when responding to a
- * {@link Intent#ACTION_SEARCH} in mode {@link #MODE_QUERY_PICK_TO_VIEW}.
- */
- private int mQueryPersonIdIndex;
+// private boolean mDisplayAll;
+ private boolean mDisplayOnlyPhones;
+
+ private Uri mGroupUri;
+
+ private long mQueryAggregateId;
+
+ private ArrayList<Long> mWritableRawContactIds = new ArrayList<Long>();
+ private int mWritableSourcesCnt;
+ private int mReadOnlySourcesCnt;
/**
* Used to keep track of the scroll state of the list.
@@ -302,8 +366,9 @@
private boolean mListHasFocus;
private String mShortcutAction;
- private boolean mDefaultMode = false;
-
+
+ private int mScrollState;
+
/**
* Internal query type when in mode {@link #MODE_QUERY_PICK_TO_VIEW}.
*/
@@ -312,52 +377,44 @@
private static final int QUERY_MODE_NONE = -1;
private static final int QUERY_MODE_MAILTO = 1;
private static final int QUERY_MODE_TEL = 2;
-
+
/**
* Data to use when in mode {@link #MODE_QUERY_PICK_TO_VIEW}. Usually
* provided by scheme-specific part of incoming {@link Intent#getData()}.
*/
private String mQueryData;
-
- private Handler mHandler = new Handler();
- private class ImportTypeSelectedListener implements DialogInterface.OnClickListener {
- public static final int IMPORT_FROM_SIM = 0;
- public static final int IMPORT_FROM_SDCARD = 1;
+ private static final String CLAUSE_ONLY_VISIBLE = Contacts.IN_VISIBLE_GROUP + "=1";
+ private static final String CLAUSE_ONLY_PHONES = Contacts.HAS_PHONE_NUMBER + "=1";
- private int mIndex;
+ /**
+ * In the {@link #MODE_JOIN} determines whether we display a list item with the label
+ * "Show all contacts" or actually show all contacts
+ */
+ private boolean mJoinModeShowAllContacts;
- public ImportTypeSelectedListener() {
- mIndex = IMPORT_FROM_SIM;
- }
+ /**
+ * The ID of the special item described above.
+ */
+ private static final long JOIN_MODE_SHOW_ALL_CONTACTS_ID = -2;
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- if (mIndex == IMPORT_FROM_SIM) {
- doImportFromSim();
- } else {
- doImportFromSDCard();
- }
- } else if (which == DialogInterface.BUTTON_NEGATIVE) {
+ // Uri matcher for contact id
+ private static final int CONTACTS_ID = 1001;
+ private static final UriMatcher sContactsIdMatcher;
- } else {
- mIndex = which;
- }
- }
+ private static ExecutorService sImageFetchThreadPool;
+
+ static {
+ sContactsIdMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ sContactsIdMatcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
}
private class DeleteClickListener implements DialogInterface.OnClickListener {
- private Uri mUri;
-
- public DeleteClickListener(Uri uri) {
- mUri = uri;
- }
-
public void onClick(DialogInterface dialog, int which) {
- getContentResolver().delete(mUri, null, null);
+ getContentResolver().delete(mSelectedContactUri, null, null);
}
}
-
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -366,18 +423,17 @@
final Intent intent = getIntent();
// Allow the title to be set to a custom String using an extra on the intent
- String title = intent.getStringExtra(Contacts.Intents.UI.TITLE_EXTRA_KEY);
+ String title = intent.getStringExtra(UI.TITLE_EXTRA_KEY);
if (title != null) {
setTitle(title);
}
-
+
final String action = intent.getAction();
mMode = MODE_UNKNOWN;
-
- setContentView(R.layout.contacts_list_content);
+ Log.i(TAG, "Called with action: " + action);
if (UI.LIST_DEFAULT.equals(action)) {
- mDefaultMode = true;
+ mMode = MODE_DEFAULT;
// When mDefaultMode is true the mode is set in onResume(), since the preferneces
// activity may change it whenever this activity isn't running
} else if (UI.LIST_GROUP_ACTION.equals(action)) {
@@ -387,9 +443,10 @@
finish();
return;
}
- buildUserGroupUris(groupName);
+ buildUserGroupUri(groupName);
} else if (UI.LIST_ALL_CONTACTS_ACTION.equals(action)) {
- mMode = MODE_ALL_CONTACTS;
+ mMode = MODE_CUSTOM;
+ mDisplayOnlyPhones = false;
} else if (UI.LIST_STARRED_ACTION.equals(action)) {
mMode = MODE_STARRED;
} else if (UI.LIST_FREQUENT_ACTION.equals(action)) {
@@ -397,17 +454,24 @@
} else if (UI.LIST_STREQUENT_ACTION.equals(action)) {
mMode = MODE_STREQUENT;
} else if (UI.LIST_CONTACTS_WITH_PHONES_ACTION.equals(action)) {
- mMode = MODE_WITH_PHONES;
+ mMode = MODE_CUSTOM;
+ mDisplayOnlyPhones = true;
} else if (Intent.ACTION_PICK.equals(action)) {
// XXX These should be showing the data from the URI given in
// the Intent.
final String type = intent.resolveType(this);
- if (People.CONTENT_TYPE.equals(type)) {
+ if (Contacts.CONTENT_TYPE.equals(type)) {
mMode = MODE_PICK_CONTACT;
- } else if (Phones.CONTENT_TYPE.equals(type)) {
+ } else if (People.CONTENT_TYPE.equals(type)) {
+ mMode = MODE_LEGACY_PICK_PERSON;
+ } else if (Phone.CONTENT_TYPE.equals(type)) {
mMode = MODE_PICK_PHONE;
- } else if (ContactMethods.CONTENT_POSTAL_TYPE.equals(type)) {
+ } else if (Phones.CONTENT_TYPE.equals(type)) {
+ mMode = MODE_LEGACY_PICK_PHONE;
+ } else if (StructuredPostal.CONTENT_TYPE.equals(type)) {
mMode = MODE_PICK_POSTAL;
+ } else if (ContactMethods.CONTENT_POSTAL_TYPE.equals(type)) {
+ mMode = MODE_LEGACY_PICK_POSTAL;
}
} else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
if (intent.getComponent().getClassName().equals("alias.DialShortcut")) {
@@ -425,13 +489,20 @@
}
} else if (Intent.ACTION_GET_CONTENT.equals(action)) {
final String type = intent.resolveType(this);
- if (People.CONTENT_ITEM_TYPE.equals(type)) {
+ if (Contacts.CONTENT_ITEM_TYPE.equals(type)) {
mMode = MODE_PICK_OR_CREATE_CONTACT;
- } else if (Phones.CONTENT_ITEM_TYPE.equals(type)) {
+ } else if (Phone.CONTENT_ITEM_TYPE.equals(type)) {
mMode = MODE_PICK_PHONE;
- } else if (ContactMethods.CONTENT_POSTAL_ITEM_TYPE.equals(type)) {
+ } else if (Phones.CONTENT_ITEM_TYPE.equals(type)) {
+ mMode = MODE_LEGACY_PICK_PHONE;
+ } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(type)) {
mMode = MODE_PICK_POSTAL;
+ } else if (ContactMethods.CONTENT_POSTAL_ITEM_TYPE.equals(type)) {
+ mMode = MODE_LEGACY_PICK_POSTAL;
+ } else if (People.CONTENT_ITEM_TYPE.equals(type)) {
+ mMode = MODE_LEGACY_PICK_OR_CREATE_PERSON;
}
+
} else if (Intent.ACTION_INSERT_OR_EDIT.equals(action)) {
mMode = MODE_INSERT_OR_EDIT_CONTACT;
} else if (Intent.ACTION_SEARCH.equals(action)) {
@@ -446,7 +517,7 @@
finish();
return;
}
-
+
// See if search request has extras to specify query
if (intent.hasExtra(Insert.EMAIL)) {
mMode = MODE_QUERY_PICK_TO_VIEW;
@@ -459,18 +530,33 @@
} else {
// Otherwise handle the more normal search case
mMode = MODE_QUERY;
+ mQueryData = getIntent().getStringExtra(SearchManager.QUERY);
}
// Since this is the filter activity it receives all intents
// dispatched from the SearchManager for security reasons
// so we need to re-dispatch from here to the intended target.
} else if (Intents.SEARCH_SUGGESTION_CLICKED.equals(action)) {
+ Uri data = intent.getData();
+ Uri telUri = null;
+ if (sContactsIdMatcher.match(data) == CONTACTS_ID) {
+ long contactId = Long.valueOf(data.getLastPathSegment());
+ final Cursor cursor = queryPhoneNumbers(contactId);
+ if (cursor != null) {
+ if (cursor.getCount() == 1 && cursor.moveToFirst()) {
+ int phoneNumberIndex = cursor.getColumnIndex(Phone.NUMBER);
+ String phoneNumber = cursor.getString(phoneNumberIndex);
+ telUri = Uri.parse("tel:" + phoneNumber);
+ }
+ cursor.close();
+ }
+ }
// See if the suggestion was clicked with a search action key (call button)
Intent newIntent;
- if ("call".equals(intent.getStringExtra(SearchManager.ACTION_MSG))) {
- newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
+ if ("call".equals(intent.getStringExtra(SearchManager.ACTION_MSG)) && telUri != null) {
+ newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, telUri);
} else {
- newIntent = new Intent(Intent.ACTION_VIEW, intent.getData());
+ newIntent = new Intent(Intent.ACTION_VIEW, data);
}
startActivity(newIntent);
finish();
@@ -481,40 +567,67 @@
finish();
return;
} else if (Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED.equals(action)) {
+ // TODO actually support this in EditContactActivity.
String number = intent.getData().getSchemeSpecificPart();
- Intent newIntent = new Intent(Intent.ACTION_INSERT, People.CONTENT_URI);
+ Intent newIntent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
newIntent.putExtra(Intents.Insert.PHONE, number);
startActivity(newIntent);
finish();
return;
}
+ if (JOIN_AGGREGATE.equals(action)) {
+ mMode = MODE_JOIN_CONTACT;
+ mQueryAggregateId = intent.getLongExtra(EXTRA_AGGREGATE_ID, -1);
+ if (mQueryAggregateId == -1) {
+ Log.e(TAG, "Intent " + action + " is missing required extra: "
+ + EXTRA_AGGREGATE_ID);
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ }
+
if (mMode == MODE_UNKNOWN) {
- mMode = DEFAULT_MODE;
+ mMode = MODE_DEFAULT;
+ }
+
+ if (mMode == MODE_JOIN_CONTACT) {
+ setContentView(R.layout.contacts_list_content_join);
+ TextView blurbView = (TextView)findViewById(R.id.join_contact_blurb);
+
+ String blurb = getString(R.string.blurbJoinContactDataWith,
+ getContactDisplayName(mQueryAggregateId));
+ blurbView.setText(blurb);
+ mJoinModeShowAllContacts = true;
+ } else {
+ setContentView(R.layout.contacts_list_content);
}
// Setup the UI
final ListView list = getListView();
+
+ // Tell list view to not show dividers. We'll do it ourself so that we can *not* show
+ // them when an A-Z headers is visible.
+ list.setDividerHeight(0);
list.setFocusable(true);
list.setOnCreateContextMenuListener(this);
if ((mMode & MODE_MASK_NO_FILTER) != MODE_MASK_NO_FILTER) {
list.setTextFilterEnabled(true);
- }
+ }
if ((mMode & MODE_MASK_CREATE_NEW) != 0) {
// Add the header for creating a new contact
final LayoutInflater inflater = getLayoutInflater();
- View header = inflater.inflate(android.R.layout.simple_list_item_1, list, false);
- TextView text = (TextView) header.findViewById(android.R.id.text1);
- text.setText(R.string.pickerNewContactHeader);
+ View header = inflater.inflate(R.layout.create_new_contact, list, false);
list.addHeaderView(header);
}
// Set the proper empty string
setEmptyText();
-
+
mAdapter = new ContactItemListAdapter(this);
setListAdapter(mAdapter);
+ getListView().setOnScrollListener(mAdapter);
// We manually save/restore the listview state
list.setSaveEnabled(false);
@@ -522,80 +635,102 @@
mQueryHandler = new QueryHandler(this);
mJustCreated = true;
- // Check to see if sync is enabled
- final ContentResolver resolver = getContentResolver();
- IContentProvider provider = resolver.acquireProvider(Contacts.CONTENT_URI);
- if (provider == null) {
- // No contacts provider, bail.
- finish();
- return;
+ // TODO(jham) redesign this
+ mSyncEnabled = true;
+// // Check to see if sync is enabled
+// final ContentResolver resolver = getContentResolver();
+// IContentProvider provider = resolver.acquireProvider(Contacts.CONTENT_URI);
+// if (provider == null) {
+// // No contacts provider, bail.
+// finish();
+// return;
+// }
+//
+// try {
+// ISyncAdapter sa = provider.getSyncAdapter();
+// mSyncEnabled = sa != null;
+// } catch (RemoteException e) {
+// mSyncEnabled = false;
+// } finally {
+// resolver.releaseProvider(provider);
+// }
+ }
+
+ private String getContactDisplayName(long contactId) {
+ String contactName = null;
+ Cursor c = getContentResolver().query(
+ ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
+ new String[] {Contacts.DISPLAY_NAME}, null, null, null);
+ try {
+ if (c != null && c.moveToFirst()) {
+ contactName = c.getString(0);
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
}
- try {
- ISyncAdapter sa = provider.getSyncAdapter();
- mSyncEnabled = sa != null;
- } catch (RemoteException e) {
- mSyncEnabled = false;
- } finally {
- resolver.releaseProvider(provider);
+ if (contactName == null) {
+ contactName = "";
+ }
+
+ return contactName;
+ }
+
+ private int[] mLocation = new int[2];
+ private Rect mRect = new Rect();
+
+ /** {@inheritDoc} */
+ public void onClick(View v) {
+ if (v.getId() == R.id.call_button) {
+ final int position = (Integer) v.getTag();
+ Cursor c = mAdapter.getCursor();
+ if (c != null) {
+ c.moveToPosition(position);
+ callContact(c);
+ }
}
}
private void setEmptyText() {
+ if (mMode == MODE_JOIN_CONTACT) {
+ return;
+ }
+
TextView empty = (TextView) findViewById(R.id.emptyText);
- // Center the text by default
- int gravity = Gravity.CENTER;
- switch (mMode) {
- case MODE_GROUP:
- if (Groups.GROUP_MY_CONTACTS.equals(mDisplayInfo)) {
- if (mSyncEnabled) {
- empty.setText(getText(R.string.noContactsHelpTextWithSync));
- } else {
- empty.setText(getText(R.string.noContactsHelpText));
- }
- gravity = Gravity.NO_GRAVITY;
+ int gravity = Gravity.NO_GRAVITY;
+
+ if (mDisplayOnlyPhones) {
+ empty.setText(getText(R.string.noContactsWithPhoneNumbers));
+ gravity = Gravity.CENTER;
+ } else if (mMode == MODE_STREQUENT || mMode == MODE_STARRED) {
+ empty.setText(getText(R.string.noFavoritesHelpText));
+ } else if (mMode == MODE_QUERY) {
+ empty.setText(getText(R.string.noMatchingContacts));
+ } else {
+ boolean hasSim = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE))
+ .hasIccCard();
+
+ if (hasSim) {
+ if (mSyncEnabled) {
+ empty.setText(getText(R.string.noContactsHelpTextWithSync));
} else {
- empty.setText(getString(R.string.groupEmpty, mDisplayInfo));
+ empty.setText(getText(R.string.noContactsHelpText));
}
- break;
-
- case MODE_STARRED:
- case MODE_STREQUENT:
- case MODE_FREQUENT:
- empty.setText(getText(R.string.noFavorites));
- break;
-
- case MODE_WITH_PHONES:
- empty.setText(getText(R.string.noContactsWithPhoneNumbers));
- break;
-
- default:
- empty.setText(getText(R.string.noContacts));
- break;
+ } else {
+ if (mSyncEnabled) {
+ empty.setText(getText(R.string.noContactsNoSimHelpTextWithSync));
+ } else {
+ empty.setText(getText(R.string.noContactsNoSimHelpText));
+ }
+ }
}
empty.setGravity(gravity);
}
- /**
- * Builds the URIs to query when displaying a user group
- *
- * @param groupName the group being displayed
- */
- private void buildUserGroupUris(String groupName) {
- mGroupFilterUri = Uri.parse("content://contacts/groups/name/" + groupName
- + "/members/filter/");
- mGroupUri = Uri.parse("content://contacts/groups/name/" + groupName + "/members");
- }
-
- /**
- * Builds the URIs to query when displaying a system group
- *
- * @param systemId the system group's ID
- */
- private void buildSystemGroupUris(String systemId) {
- mGroupFilterUri = Uri.parse("content://contacts/groups/system_id/" + systemId
- + "/members/filter/");
- mGroupUri = Uri.parse("content://contacts/groups/system_id/" + systemId + "/members");
+ private void buildUserGroupUri(String group) {
+ mGroupUri = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, group);
}
/**
@@ -604,65 +739,9 @@
private void setDefaultMode() {
// Load the preferences
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-
- // Lookup the group to display
- mDisplayType = prefs.getInt(PREF_DISPLAY_TYPE, DISPLAY_TYPE_UNKNOWN);
- switch (mDisplayType) {
- case DISPLAY_TYPE_ALL_WITH_PHONES: {
- mMode = MODE_WITH_PHONES;
- mDisplayInfo = null;
- break;
- }
- case DISPLAY_TYPE_SYSTEM_GROUP: {
- String systemId = prefs.getString(
- PREF_DISPLAY_INFO, null);
- if (!TextUtils.isEmpty(systemId)) {
- // Display the selected system group
- mMode = MODE_GROUP;
- buildSystemGroupUris(systemId);
- mDisplayInfo = systemId;
- } else {
- // No valid group is present, display everything
- mMode = MODE_WITH_PHONES;
- mDisplayInfo = null;
- mDisplayType = DISPLAY_TYPE_ALL;
- }
- break;
- }
-
- case DISPLAY_TYPE_USER_GROUP: {
- String displayGroup = prefs.getString(
- PREF_DISPLAY_INFO, null);
- if (!TextUtils.isEmpty(displayGroup)) {
- // Display the selected user group
- mMode = MODE_GROUP;
- buildUserGroupUris(displayGroup);
- mDisplayInfo = displayGroup;
- } else {
- // No valid group is present, display everything
- mMode = MODE_WITH_PHONES;
- mDisplayInfo = null;
- mDisplayType = DISPLAY_TYPE_ALL;
- }
- break;
- }
-
- case DISPLAY_TYPE_ALL: {
- mMode = MODE_ALL_CONTACTS;
- mDisplayInfo = null;
- break;
- }
-
- default: {
- // We don't know what to display, default to My Contacts
- mMode = MODE_GROUP;
- mDisplayType = DISPLAY_TYPE_SYSTEM_GROUP;
- buildSystemGroupUris(Groups.GROUP_MY_CONTACTS);
- mDisplayInfo = Groups.GROUP_MY_CONTACTS;
- break;
- }
- }
+ mDisplayOnlyPhones = prefs.getBoolean(Prefs.DISPLAY_ONLY_PHONES,
+ Prefs.DISPLAY_ONLY_PHONES_DEFAULT);
// Update the empty text view with the proper string, as the group may have changed
setEmptyText();
@@ -672,17 +751,23 @@
protected void onResume() {
super.onResume();
+ // Force cache to reload so we don't show stale photos.
+ if (mAdapter.mBitmapCache != null) {
+ mAdapter.mBitmapCache.clear();
+ }
+
+ mScrollState = OnScrollListener.SCROLL_STATE_IDLE;
boolean runQuery = true;
Activity parent = getParent();
-
+
// Do this before setting the filter. The filter thread relies
// on some state that is initialized in setDefaultMode
- if (mDefaultMode) {
+ if (mMode == MODE_DEFAULT) {
// If we're in default mode we need to possibly reset the mode due to a change
// in the preferences activity while we weren't running
setDefaultMode();
}
-
+
// See if we were invoked with a filter
if (parent != null && parent instanceof DialtactsActivity) {
String filterText = ((DialtactsActivity) parent).getAndClearFilterText();
@@ -702,7 +787,7 @@
}
mJustCreated = false;
}
-
+
@Override
protected void onRestart() {
super.onRestart();
@@ -717,15 +802,6 @@
((ContactItemListAdapter) getListAdapter()).onContentChanged();
}
}
-
- private void updateGroup() {
- if (mDefaultMode) {
- setDefaultMode();
- }
-
- // Calling requery here may cause an ANR, so always do the async query
- startQuery();
- }
@Override
protected void onSaveInstanceState(Bundle icicle) {
@@ -751,7 +827,9 @@
// be there and show up while the new query is happening. After the async query finished
// in response to onRestart() setLoading(false) will be called.
mAdapter.setLoading(true);
+ mAdapter.setSuggestionsCursor(null);
mAdapter.changeCursor(null);
+ mAdapter.clearImageFetching();
if (mMode == MODE_QUERY) {
// Make sure the search box is closed
@@ -762,160 +840,220 @@
@Override
public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+
// If Contacts was invoked by another Activity simply as a way of
// picking a contact, don't show the options menu
if ((mMode & MODE_MASK_PICKER) == MODE_MASK_PICKER) {
return false;
}
- // Search
- menu.add(0, MENU_SEARCH, 0, R.string.menu_search)
- .setIcon(android.R.drawable.ic_menu_search);
-
- // New contact
- menu.add(0, MENU_NEW_CONTACT, 0, R.string.menu_newContact)
- .setIcon(android.R.drawable.ic_menu_add)
- .setIntent(new Intent(Intents.Insert.ACTION, People.CONTENT_URI))
- .setAlphabeticShortcut('n');
-
- // Display group
- if (mDefaultMode) {
- menu.add(0, MENU_DISPLAY_GROUP, 0, R.string.menu_displayGroup)
- .setIcon(com.android.internal.R.drawable.ic_menu_allfriends);
- }
-
- // Sync settings
- if (mSyncEnabled) {
- Intent syncIntent = new Intent(Intent.ACTION_VIEW);
- syncIntent.setClass(this, ContactsGroupSyncSelector.class);
- menu.add(0, 0, 0, R.string.syncGroupPreference)
- .setIcon(com.android.internal.R.drawable.ic_menu_refresh)
- .setIntent(syncIntent);
- }
-
- // Contacts import (SIM/SDCard)
- menu.add(0, MENU_IMPORT_CONTACTS, 0, R.string.importFromSim)
- .setIcon(R.drawable.ic_menu_import_contact);
-
- if (getResources().getBoolean(R.bool.config_allow_export_to_sdcard)) {
- menu.add(0, MENU_EXPORT_CONTACTS, 0, R.string.export_contact_list)
- .setIcon(R.drawable.ic_menu_export_contact);
- }
-
- return super.onCreateOptionsMenu(menu);
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.list, menu);
+ return true;
}
- /*
- * Implements the handler for display group selection.
- */
- public void onClick(DialogInterface dialogInterface, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- // The OK button was pressed
- if (mDisplayGroupOriginalSelection != mDisplayGroupCurrentSelection) {
- // Set the group to display
- if (mDisplayGroupCurrentSelection == DISPLAY_GROUP_INDEX_ALL_CONTACTS) {
- // Display all
- mDisplayType = DISPLAY_TYPE_ALL;
- mDisplayInfo = null;
- } else if (mDisplayGroupCurrentSelection
- == DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES) {
- // Display all with phone numbers
- mDisplayType = DISPLAY_TYPE_ALL_WITH_PHONES;
- mDisplayInfo = null;
- } else if (mDisplayGroupsIncludesMyContacts &&
- mDisplayGroupCurrentSelection == DISPLAY_GROUP_INDEX_MY_CONTACTS) {
- mDisplayType = DISPLAY_TYPE_SYSTEM_GROUP;
- mDisplayInfo = Groups.GROUP_MY_CONTACTS;
- } else {
- mDisplayType = DISPLAY_TYPE_USER_GROUP;
- mDisplayInfo = mDisplayGroups[mDisplayGroupCurrentSelection].toString();
- }
-
- // Save the changes to the preferences
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- prefs.edit()
- .putInt(PREF_DISPLAY_TYPE, mDisplayType)
- .putString(PREF_DISPLAY_INFO, mDisplayInfo)
- .commit();
-
- // Update the display state
- updateGroup();
- }
- } else {
- // A list item was selected, cache the position
- mDisplayGroupCurrentSelection = which;
- }
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ final boolean defaultMode = (mMode == MODE_DEFAULT);
+ menu.findItem(R.id.menu_display_groups).setVisible(defaultMode);
+ return true;
}
-
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case MENU_DISPLAY_GROUP:
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(R.string.select_group_title)
- .setPositiveButton(android.R.string.ok, this)
- .setNegativeButton(android.R.string.cancel, null);
-
- setGroupEntries(builder);
-
- builder.show();
+ case R.id.menu_display_groups: {
+ final Intent intent = new Intent(this, DisplayGroupsActivity.class);
+ startActivityForResult(intent, SUBACTIVITY_DISPLAY_GROUP);
return true;
-
- case MENU_SEARCH:
+ }
+ case R.id.menu_search: {
startSearch(null, false, null, false);
return true;
-
- case MENU_IMPORT_CONTACTS:
- if (getResources().getBoolean(R.bool.config_allow_import_from_sdcard)) {
- ImportTypeSelectedListener listener =
- new ImportTypeSelectedListener();
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this)
- .setTitle(R.string.select_import_type_title)
- .setPositiveButton(android.R.string.ok, listener)
- .setNegativeButton(android.R.string.cancel, null);
- dialogBuilder.setSingleChoiceItems(new String[] {
- getString(R.string.import_from_sim),
- getString(R.string.import_from_sdcard)},
- ImportTypeSelectedListener.IMPORT_FROM_SIM, listener);
- dialogBuilder.show();
- } else {
- doImportFromSim();
- }
+ }
+ case R.id.menu_add: {
+ final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
+ startActivity(intent);
return true;
-
- case MENU_EXPORT_CONTACTS:
- handleExportContacts();
+ }
+ case R.id.menu_import_export: {
+ displayImportExportDialog();
+ return true;
+ }
+ case R.id.menu_accounts: {
+ final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
+ intent.putExtra(AUTHORITIES_FILTER_KEY, new String[] {
+ ContactsContract.AUTHORITY
+ });
+ startActivity(intent);
+ return true;
+ }
}
return false;
}
- private void doImportFromSim() {
- Intent importIntent = new Intent(Intent.ACTION_VIEW);
- importIntent.setType("vnd.android.cursor.item/sim-contact");
- importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
- startActivity(importIntent);
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case R.string.import_from_sim:
+ case R.string.import_from_sdcard: {
+ return AccountSelectionUtil.getSelectAccountDialog(this, id);
+ }
+ case R.id.dialog_sdcard_not_found: {
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.no_sdcard_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.no_sdcard_message)
+ .setPositiveButton(android.R.string.ok, null).create();
+ }
+ case R.id.dialog_delete_contact_confirmation: {
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.deleteConfirmation)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok,
+ new DeleteClickListener()).create();
+ }
+ case R.id.dialog_readonly_contact_hide_confirmation: {
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.readOnlyContactWarning)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok,
+ new DeleteClickListener()).create();
+ }
+ case R.id.dialog_readonly_contact_delete_confirmation: {
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.readOnlyContactDeleteConfirmation)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok,
+ new DeleteClickListener()).create();
+ }
+ case R.id.dialog_multiple_contact_delete_confirmation: {
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.multipleContactDeleteConfirmation)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok,
+ new DeleteClickListener()).create();
+ }
+ }
+ return super.onCreateDialog(id);
}
- private void doImportFromSDCard() {
- Intent intent = new Intent(this, ImportVCardActivity.class);
- startActivity(intent);
+ /**
+ * Create a {@link Dialog} that allows the user to pick from a bulk import
+ * or bulk export task across all contacts.
+ */
+ private void displayImportExportDialog() {
+ // Wrap our context to inflate list items using correct theme
+ final Context dialogContext = new ContextThemeWrapper(this, android.R.style.Theme_Light);
+ final Resources res = dialogContext.getResources();
+ final LayoutInflater dialogInflater = (LayoutInflater)dialogContext
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ // Adapter that shows a list of string resources
+ final ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(this,
+ android.R.layout.simple_list_item_1) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = dialogInflater.inflate(android.R.layout.simple_list_item_1,
+ parent, false);
+ }
+
+ final int resId = this.getItem(position);
+ ((TextView)convertView).setText(resId);
+ return convertView;
+ }
+ };
+
+ if (TelephonyManager.getDefault().hasIccCard()) {
+ adapter.add(R.string.import_from_sim);
+ }
+ if (res.getBoolean(R.bool.config_allow_import_from_sdcard)) {
+ adapter.add(R.string.import_from_sdcard);
+ }
+ if (res.getBoolean(R.bool.config_allow_export_to_sdcard)) {
+ adapter.add(R.string.export_to_sdcard);
+ }
+
+ final DialogInterface.OnClickListener clickListener =
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+
+ final int resId = adapter.getItem(which);
+ switch (resId) {
+ case R.string.import_from_sim:
+ case R.string.import_from_sdcard: {
+ handleImportRequest(resId);
+ break;
+ }
+ case R.string.export_to_sdcard: {
+ Context context = ContactsListActivity.this;
+ Intent exportIntent = new Intent(context, ExportVCardActivity.class);
+ context.startActivity(exportIntent);
+ break;
+ }
+ default: {
+ Log.e(TAG, "Unexpected resource: " +
+ getResources().getResourceEntryName(resId));
+ }
+ }
+ }
+ };
+
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.dialog_import_export)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setSingleChoiceItems(adapter, -1, clickListener)
+ .show();
}
- private void handleExportContacts() {
- VCardExporter exporter = new VCardExporter(ContactsListActivity.this, mHandler);
- exporter.startExportVCardToSdCard();
+ private void handleImportRequest(int resId) {
+ // There's three possibilities:
+ // - more than one accounts -> ask the user
+ // - just one account -> use the account without asking the user
+ // - no account -> use phone-local storage without asking the user
+ final Sources sources = Sources.getInstance(this);
+ final List<Account> accountList = sources.getAccounts(true);
+ final int size = accountList.size();
+ if (size > 1) {
+ showDialog(resId);
+ return;
+ }
+
+ AccountSelectionUtil.doImport(this, resId, (size == 1 ? accountList.get(0) : null));
}
-
+
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
switch (requestCode) {
case SUBACTIVITY_NEW_CONTACT:
if (resultCode == RESULT_OK) {
- // Contact was created, pass it back
returnPickerResult(null, data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME),
data.getData(), 0);
}
+ break;
+
+ case SUBACTIVITY_VIEW_CONTACT:
+ if (resultCode == RESULT_OK) {
+ mAdapter.notifyDataSetChanged();
+ }
+ break;
+
+ case SUBACTIVITY_DISPLAY_GROUP:
+ // Mark as just created so we re-run the view query
+ mJustCreated = true;
+ break;
}
}
@@ -941,35 +1079,27 @@
return;
}
long id = info.id;
- Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, id);
+ Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id);
+ long rawContactId = ContactsUtils.queryForRawContactId(getContentResolver(), id);
+ Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
// Setup the menu header
- menu.setHeaderTitle(cursor.getString(NAME_COLUMN_INDEX));
+ menu.setHeaderTitle(cursor.getString(SUMMARY_NAME_COLUMN_INDEX));
// View contact details
menu.add(0, MENU_ITEM_VIEW_CONTACT, 0, R.string.menu_viewContact)
- .setIntent(new Intent(Intent.ACTION_VIEW, personUri));
+ .setIntent(new Intent(Intent.ACTION_VIEW, contactUri));
- // Calling contact
- long phoneId = cursor.getLong(PRIMARY_PHONE_ID_COLUMN_INDEX);
- if (phoneId > 0) {
- // Get the display label for the number
- CharSequence label = cursor.getString(LABEL_COLUMN_INDEX);
- int type = cursor.getInt(TYPE_COLUMN_INDEX);
- label = Phones.getDisplayLabel(this, type, label);
- Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
- ContentUris.withAppendedId(Phones.CONTENT_URI, phoneId));
- menu.add(0, MENU_ITEM_CALL, 0, String.format(getString(R.string.menu_callNumber), label))
- .setIntent(intent);
-
+ if (cursor.getInt(SUMMARY_HAS_PHONE_COLUMN_INDEX) != 0) {
+ // Calling contact
+ menu.add(0, MENU_ITEM_CALL, 0,
+ getString(R.string.menu_call));
// Send SMS item
- menu.add(0, MENU_ITEM_SEND_SMS, 0, R.string.menu_sendSMS)
- .setIntent(new Intent(Intent.ACTION_SENDTO,
- Uri.fromParts("sms", cursor.getString(NUMBER_COLUMN_INDEX), null)));
+ menu.add(0, MENU_ITEM_SEND_SMS, 0, getString(R.string.menu_sendSMS));
}
// Star toggling
- int starState = cursor.getInt(STARRED_COLUMN_INDEX);
+ int starState = cursor.getInt(SUMMARY_STARRED_COLUMN_INDEX);
if (starState == 0) {
menu.add(0, MENU_ITEM_TOGGLE_STAR, 0, R.string.menu_addStar);
} else {
@@ -978,7 +1108,7 @@
// Contact editing
menu.add(0, MENU_ITEM_EDIT, 0, R.string.menu_editContact)
- .setIntent(new Intent(Intent.ACTION_EDIT, personUri));
+ .setIntent(new Intent(Intent.ACTION_EDIT, rawContactUri));
menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_deleteContact);
}
@@ -998,25 +1128,25 @@
case MENU_ITEM_TOGGLE_STAR: {
// Toggle the star
ContentValues values = new ContentValues(1);
- values.put(People.STARRED, cursor.getInt(STARRED_COLUMN_INDEX) == 0 ? 1 : 0);
- Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI,
- cursor.getInt(ID_COLUMN_INDEX));
- getContentResolver().update(personUri, values, null, null);
+ values.put(Contacts.STARRED, cursor.getInt(SUMMARY_STARRED_COLUMN_INDEX) == 0 ? 1 : 0);
+ final Uri selectedUri = this.getContactUri(info.position);
+ getContentResolver().update(selectedUri, values, null, null);
+ return true;
+ }
+
+ case MENU_ITEM_CALL: {
+ callContact(cursor);
+ return true;
+ }
+
+ case MENU_ITEM_SEND_SMS: {
+ smsContact(cursor);
return true;
}
case MENU_ITEM_DELETE: {
- // Get confirmation
- Uri uri = ContentUris.withAppendedId(People.CONTENT_URI,
- cursor.getLong(ID_COLUMN_INDEX));
- //TODO make this dialog persist across screen rotations
- new AlertDialog.Builder(ContactsListActivity.this)
- .setTitle(R.string.deleteConfirmation_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(R.string.deleteConfirmation)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(android.R.string.ok, new DeleteClickListener(uri))
- .show();
+ mSelectedContactUri = getContactUri(info.position);
+ doContactDelete();
return true;
}
}
@@ -1033,22 +1163,11 @@
}
break;
}
-
case KeyEvent.KEYCODE_DEL: {
- Object o = getListView().getSelectedItem();
- if (o != null) {
- Cursor cursor = (Cursor) o;
- Uri uri = ContentUris.withAppendedId(People.CONTENT_URI,
- cursor.getLong(ID_COLUMN_INDEX));
- //TODO make this dialog persist across screen rotations
- new AlertDialog.Builder(ContactsListActivity.this)
- .setTitle(R.string.deleteConfirmation_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(R.string.deleteConfirmation)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(android.R.string.ok, new DeleteClickListener(uri))
- .setCancelable(false)
- .show();
+ final int position = getListView().getSelectedItemPosition();
+ if (position != ListView.INVALID_POSITION) {
+ mSelectedContactUri = getContactUri(position);
+ doContactDelete();
return true;
}
break;
@@ -1058,6 +1177,46 @@
return super.onKeyDown(keyCode, event);
}
+ /**
+ * Prompt the user before deleting the given {@link Contacts} entry.
+ */
+ protected void doContactDelete() {
+ mReadOnlySourcesCnt = 0;
+ mWritableSourcesCnt = 0;
+ mWritableRawContactIds.clear();
+
+ if (mSelectedContactUri != null) {
+ Cursor c = getContentResolver().query(RawContacts.CONTENT_URI, RAW_CONTACTS_PROJECTION,
+ RawContacts.CONTACT_ID + "=" + ContentUris.parseId(mSelectedContactUri), null,
+ null);
+ Sources sources = Sources.getInstance(ContactsListActivity.this);
+ if (c != null) {
+ while (c.moveToNext()) {
+ final String accountType = c.getString(2);
+ final long rawContactId = c.getLong(0);
+ ContactsSource contactsSource = sources.getInflatedSource(accountType,
+ ContactsSource.LEVEL_SUMMARY);
+ if (contactsSource != null && contactsSource.readOnly) {
+ mReadOnlySourcesCnt += 1;
+ } else {
+ mWritableSourcesCnt += 1;
+ mWritableRawContactIds.add(rawContactId);
+ }
+ }
+ }
+ c.close();
+ if (mReadOnlySourcesCnt > 0 && mWritableSourcesCnt > 0) {
+ showDialog(R.id.dialog_readonly_contact_delete_confirmation);
+ } else if (mReadOnlySourcesCnt > 0 && mWritableSourcesCnt == 0) {
+ showDialog(R.id.dialog_readonly_contact_hide_confirmation);
+ } else if (mReadOnlySourcesCnt == 0 && mWritableSourcesCnt > 1) {
+ showDialog(R.id.dialog_multiple_contact_delete_confirmation);
+ } else {
+ showDialog(R.id.dialog_delete_contact_confirmation);
+ }
+ }
+ }
+
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// Hide soft keyboard, if visible
@@ -1068,75 +1227,89 @@
if (mMode == MODE_INSERT_OR_EDIT_CONTACT) {
Intent intent;
if (position == 0) {
- // Insert
- intent = new Intent(Intent.ACTION_INSERT, People.CONTENT_URI);
+ intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
} else {
- // Edit
- intent = new Intent(Intent.ACTION_EDIT,
- ContentUris.withAppendedId(People.CONTENT_URI, id));
+ // Edit. adjusting position by subtracting header view count.
+ position -= getListView().getHeaderViewsCount();
+ final Uri uri = getSelectedUri(position);
+ intent = new Intent(Intent.ACTION_EDIT, uri);
}
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
- final Bundle extras = getIntent().getExtras();
- if (extras != null) {
- intent.putExtras(extras);
+ Bundle extras = getIntent().getExtras();
+
+ if (extras == null) {
+ extras = new Bundle();
}
+ intent.putExtras(extras);
+ extras.putBoolean(KEY_PICKER_MODE, (mMode & MODE_MASK_PICKER) == MODE_MASK_PICKER);
+
startActivity(intent);
finish();
} else if (id != -1) {
+ // Subtract one if we have Create Contact at the top
+ if ((mMode & MODE_MASK_CREATE_NEW) != 0) {
+ position--;
+ }
+ final Uri uri = getSelectedUri(position);
if ((mMode & MODE_MASK_PICKER) == 0) {
- Intent intent = new Intent(Intent.ACTION_VIEW,
- ContentUris.withAppendedId(People.CONTENT_URI, id));
- startActivity(intent);
+ final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ startActivityForResult(intent, SUBACTIVITY_VIEW_CONTACT);
+ } else if (mMode == MODE_JOIN_CONTACT) {
+ if (id == JOIN_MODE_SHOW_ALL_CONTACTS_ID) {
+ mJoinModeShowAllContacts = false;
+ startQuery();
+ } else {
+ returnPickerResult(null, null, uri, id);
+ }
} else if (mMode == MODE_QUERY_PICK_TO_VIEW) {
// Started with query that should launch to view contact
- Cursor c = (Cursor) mAdapter.getItem(position);
- long personId = c.getLong(mQueryPersonIdIndex);
- Intent intent = new Intent(Intent.ACTION_VIEW,
- ContentUris.withAppendedId(People.CONTENT_URI, personId));
+ final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
finish();
- } else if (mMode == MODE_PICK_CONTACT
- || mMode == MODE_PICK_OR_CREATE_CONTACT) {
- Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, id);
+ } else if (mMode == MODE_PICK_CONTACT
+ || mMode == MODE_PICK_OR_CREATE_CONTACT
+ || mMode == MODE_LEGACY_PICK_PERSON
+ || mMode == MODE_LEGACY_PICK_OR_CREATE_PERSON) {
if (mShortcutAction != null) {
- // Subtract one if we have Create Contact at the top
- Cursor c = (Cursor) mAdapter.getItem(position
- - (mMode == MODE_PICK_OR_CREATE_CONTACT? 1:0));
- returnPickerResult(c, c.getString(NAME_COLUMN_INDEX), uri, id);
+ Cursor c = (Cursor) mAdapter.getItem(position);
+ returnPickerResult(c, c.getString(SUMMARY_NAME_COLUMN_INDEX), uri, id);
} else {
returnPickerResult(null, null, uri, id);
}
} else if (mMode == MODE_PICK_PHONE) {
- Uri uri = ContentUris.withAppendedId(Phones.CONTENT_URI, id);
if (mShortcutAction != null) {
Cursor c = (Cursor) mAdapter.getItem(position);
- returnPickerResult(c, c.getString(NAME_COLUMN_INDEX), uri, id);
+ returnPickerResult(c, c.getString(PHONE_DISPLAY_NAME_COLUMN_INDEX), uri, id);
} else {
returnPickerResult(null, null, uri, id);
}
- } else if (mMode == MODE_PICK_POSTAL) {
- setResult(RESULT_OK, new Intent().setData(
- ContentUris.withAppendedId(ContactMethods.CONTENT_URI, id)));
- finish();
+ } else if (mMode == MODE_PICK_POSTAL
+ || mMode == MODE_LEGACY_PICK_POSTAL
+ || mMode == MODE_LEGACY_PICK_PHONE) {
+ returnPickerResult(null, null, uri, id);
}
} else if ((mMode & MODE_MASK_CREATE_NEW) == MODE_MASK_CREATE_NEW
&& position == 0) {
- Intent newContact = new Intent(Intents.Insert.ACTION, People.CONTENT_URI);
+ Intent newContact = new Intent(Intents.Insert.ACTION, Contacts.CONTENT_URI);
startActivityForResult(newContact, SUBACTIVITY_NEW_CONTACT);
} else {
signalError();
}
}
+ /**
+ * @param uri In most cases, this should be a lookup {@link Uri}, possibly
+ * generated through {@link Contacts#getLookupUri(long, String)}.
+ */
private void returnPickerResult(Cursor c, String name, Uri uri, long id) {
final Intent intent = new Intent();
-
+
if (mShortcutAction != null) {
Intent shortcutIntent;
if (Intent.ACTION_VIEW.equals(mShortcutAction)) {
// This is a simple shortcut to view a contact.
shortcutIntent = new Intent(mShortcutAction, uri);
- final Bitmap icon = People.loadContactPhoto(this, uri, 0, null);
+ final Bitmap icon = loadContactPhoto(id, null);
if (icon != null) {
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);
} else {
@@ -1146,27 +1319,26 @@
}
} else {
// This is a direct dial or sms shortcut.
- String number = c.getString(DATA_COLUMN_INDEX);
- int type = c.getInt(TYPE_COLUMN_INDEX);
+ String number = c.getString(PHONE_NUMBER_COLUMN_INDEX);
+ int type = c.getInt(PHONE_TYPE_COLUMN_INDEX);
String scheme;
int resid;
if (Intent.ACTION_CALL.equals(mShortcutAction)) {
- scheme = "tel";
+ scheme = Constants.SCHEME_TEL;
resid = R.drawable.badge_action_call;
} else {
- scheme = "smsto";
+ scheme = Constants.SCHEME_SMSTO;
resid = R.drawable.badge_action_sms;
}
+
// Make the URI a direct tel: URI so that it will always continue to work
Uri phoneUri = Uri.fromParts(scheme, number, null);
shortcutIntent = new Intent(mShortcutAction, phoneUri);
-
- // Find the People._ID for this phone number
- final long personId = c.getLong(PHONES_PERSON_ID_INDEX);
- Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, personId);
+
+ // Find the Contacts._ID for this phone number
+ long contactId = c.getLong(PHONE_CONTACT_ID_COLUMN_INDEX);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON,
- generatePhoneNumberIcon(personUri, type, resid));
-
+ generatePhoneNumberIcon(contactId, type, resid));
}
shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
@@ -1182,16 +1354,17 @@
* Generates a phone number shortcut icon. Adds an overlay describing the type of the phone
* number, and if there is a photo also adds the call action icon.
*
- * @param personUri The person the phone number belongs to
+ * @param contactId The person the phone number belongs to
* @param type The type of the phone number
* @param actionResId The ID for the action resource
* @return The bitmap for the icon
*/
- private Bitmap generatePhoneNumberIcon(Uri personUri, int type, int actionResId) {
+ private Bitmap generatePhoneNumberIcon(long contactId, int type, int actionResId) {
final Resources r = getResources();
boolean drawPhoneOverlay = true;
+ final float scaleDensity = getResources().getDisplayMetrics().scaledDensity;
- Bitmap photo = People.loadContactPhoto(this, personUri, 0, null);
+ Bitmap photo = loadContactPhoto(contactId, null);
if (photo == null) {
// If there isn't a photo use the generic phone action icon instead
Bitmap phoneIcon = getPhoneActionIcon(r, actionResId);
@@ -1219,42 +1392,43 @@
// Create an overlay for the phone number type
String overlay = null;
switch (type) {
- case Phones.TYPE_HOME:
- overlay = "H";
+ case Phone.TYPE_HOME:
+ overlay = getString(R.string.type_short_home);
break;
- case Phones.TYPE_MOBILE:
- overlay = "M";
+ case Phone.TYPE_MOBILE:
+ overlay = getString(R.string.type_short_mobile);
break;
- case Phones.TYPE_WORK:
- overlay = "W";
+ case Phone.TYPE_WORK:
+ overlay = getString(R.string.type_short_work);
break;
- case Phones.TYPE_PAGER:
- overlay = "P";
+ case Phone.TYPE_PAGER:
+ overlay = getString(R.string.type_short_pager);
break;
- case Phones.TYPE_OTHER:
- overlay = "O";
+ case Phone.TYPE_OTHER:
+ overlay = getString(R.string.type_short_other);
break;
}
if (overlay != null) {
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
- textPaint.setTextSize(20.0f);
+ textPaint.setTextSize(20.0f * scaleDensity);
textPaint.setTypeface(Typeface.DEFAULT_BOLD);
textPaint.setColor(r.getColor(R.color.textColorIconOverlay));
textPaint.setShadowLayer(3f, 1, 1, r.getColor(R.color.textColorIconOverlayShadow));
- canvas.drawText(overlay, 2, 16, textPaint);
+ canvas.drawText(overlay, 2 * scaleDensity, 16 * scaleDensity, textPaint);
}
// Draw the phone action icon as an overlay
if (ENABLE_ACTION_ICON_OVERLAYS && drawPhoneOverlay) {
Bitmap phoneIcon = getPhoneActionIcon(r, actionResId);
if (phoneIcon != null) {
- src.set(0,0, phoneIcon.getWidth(),phoneIcon.getHeight());
+ src.set(0, 0, phoneIcon.getWidth(), phoneIcon.getHeight());
int iconWidth = icon.getWidth();
- dst.set(iconWidth - 20, -1, iconWidth, 19);
+ dst.set(iconWidth - ((int) (20 * scaleDensity)), -1,
+ iconWidth, ((int) (19 * scaleDensity)));
canvas.drawBitmap(phoneIcon, src, dst, photoPaint);
}
}
@@ -1278,30 +1452,197 @@
return null;
}
}
-
- String[] getProjection() {
- switch (mMode) {
- case MODE_GROUP:
- case MODE_ALL_CONTACTS:
- case MODE_WITH_PHONES:
- case MODE_PICK_CONTACT:
- case MODE_PICK_OR_CREATE_CONTACT:
- case MODE_QUERY:
- case MODE_STARRED:
+
+ Uri getUriToQuery() {
+ switch(mMode) {
+ case MODE_JOIN_CONTACT:
+ return getJoinSuggestionsUri(null);
case MODE_FREQUENT:
+ case MODE_STARRED:
+ case MODE_DEFAULT:
case MODE_INSERT_OR_EDIT_CONTACT:
- return CONTACTS_PROJECTION;
-
- case MODE_STREQUENT:
- return STREQUENT_PROJECTION;
-
- case MODE_PICK_PHONE:
- return PHONES_PROJECTION;
-
- case MODE_PICK_POSTAL:
- return CONTACT_METHODS_PROJECTION;
+ case MODE_PICK_CONTACT:
+ case MODE_PICK_OR_CREATE_CONTACT:{
+ return Contacts.CONTENT_URI;
+ }
+ case MODE_STREQUENT: {
+ return Contacts.CONTENT_STREQUENT_URI;
+ }
+ case MODE_LEGACY_PICK_PERSON:
+ case MODE_LEGACY_PICK_OR_CREATE_PERSON: {
+ return People.CONTENT_URI;
+ }
+ case MODE_PICK_PHONE: {
+ return Phone.CONTENT_URI;
+ }
+ case MODE_LEGACY_PICK_PHONE: {
+ return Phones.CONTENT_URI;
+ }
+ case MODE_PICK_POSTAL: {
+ return StructuredPostal.CONTENT_URI;
+ }
+ case MODE_LEGACY_PICK_POSTAL: {
+ return ContactMethods.CONTENT_URI;
+ }
+ case MODE_QUERY_PICK_TO_VIEW: {
+ if (mQueryMode == QUERY_MODE_MAILTO) {
+ return Uri.withAppendedPath(Email.CONTENT_FILTER_URI, Uri.encode(mQueryData));
+ } else if (mQueryMode == QUERY_MODE_TEL) {
+ return Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, Uri.encode(mQueryData));
+ }
+ }
+ case MODE_QUERY: {
+ return getContactFilterUri(mQueryData);
+ }
+ case MODE_GROUP: {
+ return mGroupUri;
+ }
+ default: {
+ throw new IllegalStateException("Can't generate URI: Unsupported Mode.");
+ }
}
- return null;
+ }
+
+ /**
+ * Build the {@link Contacts#CONTENT_LOOKUP_URI} for the given
+ * {@link ListView} position, using {@link #mAdapter}.
+ */
+ private Uri getContactUri(int position) {
+ if (position == ListView.INVALID_POSITION) {
+ throw new IllegalArgumentException("Position not in list bounds");
+ }
+
+ final Cursor cursor = (Cursor)mAdapter.getItem(position);
+ switch(mMode) {
+ case MODE_LEGACY_PICK_PERSON:
+ case MODE_LEGACY_PICK_OR_CREATE_PERSON: {
+ final long personId = cursor.getLong(SUMMARY_ID_COLUMN_INDEX);
+ return ContentUris.withAppendedId(People.CONTENT_URI, personId);
+ }
+
+ default: {
+ // Build and return soft, lookup reference
+ final long contactId = cursor.getLong(SUMMARY_ID_COLUMN_INDEX);
+ final String lookupKey = cursor.getString(SUMMARY_LOOKUP_KEY);
+ return Contacts.getLookupUri(contactId, lookupKey);
+ }
+ }
+ }
+
+ /**
+ * Build the {@link Uri} for the given {@link ListView} position, which can
+ * be used as result when in {@link #MODE_MASK_PICKER} mode.
+ */
+ private Uri getSelectedUri(int position) {
+ if (position == ListView.INVALID_POSITION) {
+ throw new IllegalArgumentException("Position not in list bounds");
+ }
+
+ final long id = mAdapter.getItemId(position);
+ switch(mMode) {
+ case MODE_LEGACY_PICK_PERSON:
+ case MODE_LEGACY_PICK_OR_CREATE_PERSON: {
+ return ContentUris.withAppendedId(People.CONTENT_URI, id);
+ }
+ case MODE_PICK_PHONE: {
+ return ContentUris.withAppendedId(Data.CONTENT_URI, id);
+ }
+ case MODE_LEGACY_PICK_PHONE: {
+ return ContentUris.withAppendedId(Phones.CONTENT_URI, id);
+ }
+ case MODE_PICK_POSTAL: {
+ return ContentUris.withAppendedId(Data.CONTENT_URI, id);
+ }
+ case MODE_LEGACY_PICK_POSTAL: {
+ return ContentUris.withAppendedId(ContactMethods.CONTENT_URI, id);
+ }
+ default: {
+ return getContactUri(position);
+ }
+ }
+ }
+
+ String[] getProjectionForQuery() {
+ switch(mMode) {
+ case MODE_JOIN_CONTACT:
+ case MODE_STREQUENT:
+ case MODE_FREQUENT:
+ case MODE_STARRED:
+ case MODE_QUERY:
+ case MODE_DEFAULT:
+ case MODE_INSERT_OR_EDIT_CONTACT:
+ case MODE_GROUP:
+ case MODE_PICK_CONTACT:
+ case MODE_PICK_OR_CREATE_CONTACT: {
+ return CONTACTS_SUMMARY_PROJECTION;
+ }
+ case MODE_LEGACY_PICK_PERSON:
+ case MODE_LEGACY_PICK_OR_CREATE_PERSON: {
+ return LEGACY_PEOPLE_PROJECTION ;
+ }
+ case MODE_PICK_PHONE: {
+ return PHONES_PROJECTION;
+ }
+ case MODE_LEGACY_PICK_PHONE: {
+ return LEGACY_PHONES_PROJECTION;
+ }
+ case MODE_PICK_POSTAL: {
+ return POSTALS_PROJECTION;
+ }
+ case MODE_LEGACY_PICK_POSTAL: {
+ return LEGACY_POSTALS_PROJECTION;
+ }
+ case MODE_QUERY_PICK_TO_VIEW: {
+ if (mQueryMode == QUERY_MODE_MAILTO) {
+ return CONTACTS_SUMMARY_PROJECTION_FROM_EMAIL;
+ } else if (mQueryMode == QUERY_MODE_TEL) {
+ return PHONES_PROJECTION;
+ }
+ break;
+ }
+ }
+
+ // Default to normal aggregate projection
+ return CONTACTS_SUMMARY_PROJECTION;
+ }
+
+ private Bitmap loadContactPhoto(long contactId, BitmapFactory.Options options) {
+ Cursor cursor = null;
+ Bitmap bm = null;
+ try {
+ Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+ Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
+ cursor = getContentResolver().query(photoUri, new String[] {Photo.PHOTO},
+ null, null, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ bm = ContactsUtils.loadContactPhoto(cursor, 0, options);
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return bm;
+ }
+
+ /**
+ * Return the selection arguments for a default query based on
+ * {@link #mDisplayAll} and {@link #mDisplayOnlyPhones} flags.
+ */
+ private String getContactSelection() {
+ if (mDisplayOnlyPhones) {
+ return CLAUSE_ONLY_VISIBLE + " AND " + CLAUSE_ONLY_PHONES;
+ } else {
+ return CLAUSE_ONLY_VISIBLE;
+ }
+ }
+
+ private Uri getContactFilterUri(String filter) {
+ if (!TextUtils.isEmpty(filter)) {
+ return Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(filter));
+ } else {
+ return Contacts.CONTENT_URI;
+ }
}
private Uri getPeopleFilterUri(String filter) {
@@ -1312,178 +1653,214 @@
}
}
+ private Uri getJoinSuggestionsUri(String filter) {
+ Builder builder = Contacts.CONTENT_URI.buildUpon();
+ builder.appendEncodedPath(String.valueOf(mQueryAggregateId));
+ builder.appendEncodedPath(AggregationSuggestions.CONTENT_DIRECTORY);
+ if (!TextUtils.isEmpty(filter)) {
+ builder.appendEncodedPath(Uri.encode(filter));
+ }
+ builder.appendQueryParameter("limit", String.valueOf(MAX_SUGGESTIONS));
+ return builder.build();
+ }
+
private static String getSortOrder(String[] projectionType) {
- if (Locale.getDefault().equals(Locale.JAPAN) &&
- projectionType == CONTACTS_PROJECTION) {
+ /* if (Locale.getDefault().equals(Locale.JAPAN) &&
+ projectionType == AGGREGATES_PRIMARY_PHONE_PROJECTION) {
return SORT_STRING + " ASC";
} else {
return NAME_COLUMN + " COLLATE LOCALIZED ASC";
- }
+ } */
+
+ return NAME_COLUMN + " COLLATE LOCALIZED ASC";
}
-
+
void startQuery() {
mAdapter.setLoading(true);
-
+
// Cancel any pending queries
mQueryHandler.cancelOperation(QUERY_TOKEN);
+ mQueryHandler.setLoadingJoinSuggestions(false);
+
+ String[] projection = getProjectionForQuery();
+ String callingPackage = getCallingPackage();
+ Uri uri = getUriToQuery();
+ if (!TextUtils.isEmpty(callingPackage)) {
+ uri = uri.buildUpon()
+ .appendQueryParameter(ContactsContract.REQUESTING_PACKAGE_PARAM_KEY,
+ callingPackage)
+ .build();
+ }
// Kick off the new query
switch (mMode) {
case MODE_GROUP:
mQueryHandler.startQuery(QUERY_TOKEN, null,
- mGroupUri, CONTACTS_PROJECTION, null, null,
- getSortOrder(CONTACTS_PROJECTION));
+ uri, projection, getContactSelection(), null,
+ getSortOrder(projection));
break;
- case MODE_ALL_CONTACTS:
+ case MODE_DEFAULT:
case MODE_PICK_CONTACT:
case MODE_PICK_OR_CREATE_CONTACT:
case MODE_INSERT_OR_EDIT_CONTACT:
- mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI, CONTACTS_PROJECTION,
- null, null, getSortOrder(CONTACTS_PROJECTION));
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
+ projection, getContactSelection(), null,
+ getSortOrder(projection));
break;
- case MODE_WITH_PHONES:
- mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI, CONTACTS_PROJECTION,
- People.PRIMARY_PHONE_ID + " IS NOT NULL", null,
- getSortOrder(CONTACTS_PROJECTION));
+ case MODE_LEGACY_PICK_PERSON:
+ case MODE_LEGACY_PICK_OR_CREATE_PERSON:
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
+ projection, null, null,
+ getSortOrder(projection));
break;
case MODE_QUERY: {
- mQuery = getIntent().getStringExtra(SearchManager.QUERY);
- mQueryHandler.startQuery(QUERY_TOKEN, null, getPeopleFilterUri(mQuery),
- CONTACTS_PROJECTION, null, null,
- getSortOrder(CONTACTS_PROJECTION));
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
+ projection, null, null,
+ getSortOrder(projection));
break;
}
-
+
case MODE_QUERY_PICK_TO_VIEW: {
- if (mQueryMode == QUERY_MODE_MAILTO) {
- // Find all contacts with the given search string as either
- // an E-mail or IM address.
- mQueryPersonIdIndex = SIMPLE_CONTACTS_PERSON_ID_INDEX;
- Uri uri = Uri.withAppendedPath(People.WITH_EMAIL_OR_IM_FILTER_URI,
- Uri.encode(mQueryData));
- mQueryHandler.startQuery(QUERY_TOKEN, null,
- uri, SIMPLE_CONTACTS_PROJECTION, null, null,
- getSortOrder(CONTACTS_PROJECTION));
-
- } else if (mQueryMode == QUERY_MODE_TEL) {
- mQueryPersonIdIndex = PHONES_PERSON_ID_INDEX;
- mQueryHandler.startQuery(QUERY_TOKEN, null,
- Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, mQueryData),
- PHONES_PROJECTION, null, null,
- getSortOrder(PHONES_PROJECTION));
- }
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri, projection, null, null,
+ getSortOrder(projection));
break;
}
-
+
case MODE_STARRED:
- mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI,
- CONTACTS_PROJECTION,
- People.STARRED + "=1", null, getSortOrder(CONTACTS_PROJECTION));
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
+ projection, Contacts.STARRED + "=1", null,
+ getSortOrder(projection));
break;
case MODE_FREQUENT:
- mQueryHandler.startQuery(QUERY_TOKEN, null,
- People.CONTENT_URI, CONTACTS_PROJECTION,
- People.TIMES_CONTACTED + " > 0", null,
- People.TIMES_CONTACTED + " DESC, " + getSortOrder(CONTACTS_PROJECTION));
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
+ projection,
+ Contacts.TIMES_CONTACTED + " > 0", null,
+ Contacts.TIMES_CONTACTED + " DESC, "
+ + getSortOrder(projection));
break;
case MODE_STREQUENT:
- mQueryHandler.startQuery(QUERY_TOKEN, null,
- Uri.withAppendedPath(People.CONTENT_URI, "strequent"), STREQUENT_PROJECTION,
- null, null, null);
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri, projection, null, null, null);
break;
case MODE_PICK_PHONE:
- mQueryHandler.startQuery(QUERY_TOKEN, null, Phones.CONTENT_URI, PHONES_PROJECTION,
- null, null, getSortOrder(PHONES_PROJECTION));
+ case MODE_LEGACY_PICK_PHONE:
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
+ projection, null, null, getSortOrder(projection));
break;
case MODE_PICK_POSTAL:
- mQueryHandler.startQuery(QUERY_TOKEN, null, ContactMethods.CONTENT_URI,
- CONTACT_METHODS_PROJECTION,
- ContactMethods.KIND + "=" + Contacts.KIND_POSTAL, null,
- getSortOrder(CONTACT_METHODS_PROJECTION));
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
+ projection, null, null, getSortOrder(projection));
+ break;
+
+ case MODE_LEGACY_PICK_POSTAL:
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
+ projection,
+ ContactMethods.KIND + "=" + android.provider.Contacts.KIND_POSTAL, null,
+ getSortOrder(projection));
+ break;
+
+ case MODE_JOIN_CONTACT:
+ mQueryHandler.setLoadingJoinSuggestions(true);
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri, projection,
+ null, null, null);
break;
}
}
/**
* Called from a background thread to do the filter and return the resulting cursor.
- *
+ *
* @param filter the text that was entered to filter on
* @return a cursor with the results of the filter
*/
Cursor doFilter(String filter) {
final ContentResolver resolver = getContentResolver();
- switch (mMode) {
- case MODE_GROUP: {
- Uri uri;
- if (TextUtils.isEmpty(filter)) {
- uri = mGroupUri;
- } else {
- uri = Uri.withAppendedPath(mGroupFilterUri, Uri.encode(filter));
- }
- return resolver.query(uri, CONTACTS_PROJECTION, null, null,
- getSortOrder(CONTACTS_PROJECTION));
- }
+ String[] projection = getProjectionForQuery();
- case MODE_ALL_CONTACTS:
+ switch (mMode) {
+ case MODE_DEFAULT:
case MODE_PICK_CONTACT:
case MODE_PICK_OR_CREATE_CONTACT:
case MODE_INSERT_OR_EDIT_CONTACT: {
- return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION, null, null,
- getSortOrder(CONTACTS_PROJECTION));
+ return resolver.query(getContactFilterUri(filter), projection,
+ getContactSelection(), null, getSortOrder(projection));
}
- case MODE_WITH_PHONES: {
- return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION,
- People.PRIMARY_PHONE_ID + " IS NOT NULL", null,
- getSortOrder(CONTACTS_PROJECTION));
+ case MODE_LEGACY_PICK_PERSON:
+ case MODE_LEGACY_PICK_OR_CREATE_PERSON: {
+ return resolver.query(getPeopleFilterUri(filter), projection, null, null,
+ getSortOrder(projection));
}
case MODE_STARRED: {
- return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION,
- People.STARRED + "=1", null, getSortOrder(CONTACTS_PROJECTION));
+ return resolver.query(getContactFilterUri(filter), projection,
+ Contacts.STARRED + "=1", null,
+ getSortOrder(projection));
}
case MODE_FREQUENT: {
- return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION,
- People.TIMES_CONTACTED + " > 0", null,
- People.TIMES_CONTACTED + " DESC, " + getSortOrder(CONTACTS_PROJECTION));
-
+ return resolver.query(getContactFilterUri(filter), projection,
+ Contacts.TIMES_CONTACTED + " > 0", null,
+ Contacts.TIMES_CONTACTED + " DESC, "
+ + getSortOrder(projection));
}
case MODE_STREQUENT: {
Uri uri;
if (!TextUtils.isEmpty(filter)) {
- uri = Uri.withAppendedPath(People.CONTENT_URI, "strequent/filter/"
- + Uri.encode(filter));
+ uri = Uri.withAppendedPath(Contacts.CONTENT_STREQUENT_FILTER_URI,
+ Uri.encode(filter));
} else {
- uri = Uri.withAppendedPath(People.CONTENT_URI, "strequent");
+ uri = Contacts.CONTENT_STREQUENT_URI;
}
- return resolver.query(uri, STREQUENT_PROJECTION, null, null, null);
+ return resolver.query(uri, projection, null, null, null);
}
case MODE_PICK_PHONE: {
- Uri uri;
+ Uri uri = getUriToQuery();
if (!TextUtils.isEmpty(filter)) {
- uri = Uri.withAppendedPath(Phones.CONTENT_URI, "filter_name/"
- + Uri.encode(filter));
- } else {
- uri = Phones.CONTENT_URI;
+ uri = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, Uri.encode(filter));
}
- return resolver.query(uri, PHONES_PROJECTION, null, null,
- getSortOrder(PHONES_PROJECTION));
+ return resolver.query(uri, projection, null, null,
+ getSortOrder(projection));
+ }
+
+ case MODE_LEGACY_PICK_PHONE: {
+ //TODO: Support filtering here (bug 2092503)
+ break;
+ }
+
+ case MODE_JOIN_CONTACT: {
+
+ // We are on a background thread. Run queries one after the other synchronously
+ Cursor cursor = resolver.query(getJoinSuggestionsUri(filter), projection, null,
+ null, null);
+ mAdapter.setSuggestionsCursor(cursor);
+ mJoinModeShowAllContacts = false;
+ return resolver.query(getContactFilterUri(filter), projection,
+ Contacts._ID + " != " + mQueryAggregateId + " AND " + CLAUSE_ONLY_VISIBLE,
+ null, getSortOrder(projection));
}
}
throw new UnsupportedOperationException("filtering not allowed in mode " + mMode);
}
+ private Cursor getShowAllContactsLabelCursor(String[] projection) {
+ MatrixCursor matrixCursor = new MatrixCursor(projection);
+ Object[] row = new Object[projection.length];
+ // The only columns we care about is the id
+ row[SUMMARY_ID_COLUMN_INDEX] = JOIN_MODE_SHOW_ALL_CONTACTS_ID;
+ matrixCursor.addRow(row);
+ return matrixCursor;
+ }
+
/**
* Calls the currently selected list item.
* @return true if the call was initiated, false otherwise
@@ -1492,23 +1869,86 @@
ListView list = getListView();
if (list.hasFocus()) {
Cursor cursor = (Cursor) list.getSelectedItem();
- if (cursor != null) {
- long phoneId = cursor.getLong(PRIMARY_PHONE_ID_COLUMN_INDEX);
- if (phoneId == 0) {
- // There is no phone number.
- signalError();
- return false;
- }
- Uri uri = ContentUris.withAppendedId(Phones.CONTENT_URI, phoneId);
- Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, uri);
- startActivity(intent);
- return true;
+ return callContact(cursor);
+ }
+ return false;
+ }
+
+ boolean callContact(Cursor cursor) {
+ return callOrSmsContact(cursor, false /*call*/);
+ }
+
+ boolean smsContact(Cursor cursor) {
+ return callOrSmsContact(cursor, true /*sms*/);
+ }
+
+ /**
+ * Calls the contact which the cursor is point to.
+ * @return true if the call was initiated, false otherwise
+ */
+ boolean callOrSmsContact(Cursor cursor, boolean sendSms) {
+ if (cursor != null) {
+ boolean hasPhone = cursor.getInt(SUMMARY_HAS_PHONE_COLUMN_INDEX) != 0;
+ if (!hasPhone) {
+ // There is no phone number.
+ signalError();
+ return false;
}
+
+ String phone = null;
+ Cursor phonesCursor = null;
+ phonesCursor = queryPhoneNumbers(cursor.getLong(SUMMARY_ID_COLUMN_INDEX));
+ if (phonesCursor == null || phonesCursor.getCount() == 0) {
+ // No valid number
+ signalError();
+ return false;
+ } else if (phonesCursor.getCount() == 1) {
+ // only one number, call it.
+ phone = phonesCursor.getString(phonesCursor.getColumnIndex(Phone.NUMBER));
+ } else {
+ phonesCursor.moveToPosition(-1);
+ while (phonesCursor.moveToNext()) {
+ if (phonesCursor.getInt(phonesCursor.
+ getColumnIndex(Phone.IS_SUPER_PRIMARY)) != 0) {
+ // Found super primary, call it.
+ phone = phonesCursor.
+ getString(phonesCursor.getColumnIndex(Phone.NUMBER));
+ break;
+ }
+ }
+ }
+
+ if (phone == null) {
+ // Display dialog to choose a number to call.
+ PhoneDisambigDialog phoneDialog = new PhoneDisambigDialog(
+ this, phonesCursor, sendSms);
+ phoneDialog.show();
+ } else {
+ if (sendSms) {
+ ContactsUtils.initiateSms(this, phone);
+ } else {
+ ContactsUtils.initiateCall(this, phone);
+ }
+ }
+ return true;
}
return false;
}
+ private Cursor queryPhoneNumbers(long contactId) {
+ Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+ Uri dataUri = Uri.withAppendedPath(baseUri, Contacts.Data.CONTENT_DIRECTORY);
+
+ Cursor c = getContentResolver().query(dataUri,
+ new String[] {Phone._ID, Phone.NUMBER, Phone.IS_SUPER_PRIMARY},
+ Data.MIMETYPE + "=?", new String[] {Phone.CONTENT_ITEM_TYPE}, null);
+ if (c != null && c.moveToFirst()) {
+ return c;
+ }
+ return null;
+ }
+
/**
* Signal an error to the user.
*/
@@ -1525,98 +1965,53 @@
return (Cursor) listView.getAdapter().getItem(index);
}
- private void setGroupEntries(AlertDialog.Builder builder) {
- boolean syncEverything;
- // For now we only support a single account and the UI doesn't know what
- // the account name is, so we're using a global setting for SYNC_EVERYTHING.
- // Some day when we add multiple accounts to the UI this should use the per
- // account setting.
- String value = Contacts.Settings.getSetting(getContentResolver(), null,
- Contacts.Settings.SYNC_EVERYTHING);
- if (value == null) {
- // If nothing is set yet we default to syncing everything
- syncEverything = true;
- } else {
- syncEverything = !TextUtils.isEmpty(value) && !"0".equals(value);
- }
-
- Cursor cursor;
- if (!syncEverything) {
- cursor = getContentResolver().query(Groups.CONTENT_URI, GROUPS_PROJECTION,
- Groups.SHOULD_SYNC + " != 0", null, Groups.DEFAULT_SORT_ORDER);
- } else {
- cursor = getContentResolver().query(Groups.CONTENT_URI, GROUPS_PROJECTION,
- null, null, Groups.DEFAULT_SORT_ORDER);
- }
- try {
- ArrayList<CharSequence> groups = new ArrayList<CharSequence>();
- ArrayList<CharSequence> prefStrings = new ArrayList<CharSequence>();
-
- // Add All Contacts
- groups.add(DISPLAY_GROUP_INDEX_ALL_CONTACTS, getString(R.string.showAllGroups));
- prefStrings.add("");
-
- // Add Contacts with phones
- groups.add(DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES,
- getString(R.string.groupNameWithPhones));
- prefStrings.add(GROUP_WITH_PHONES);
-
- int currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS;
- while (cursor.moveToNext()) {
- String systemId = cursor.getString(GROUPS_COLUMN_INDEX_SYSTEM_ID);
- String name = cursor.getString(GROUPS_COLUMN_INDEX_NAME);
- if (cursor.isNull(GROUPS_COLUMN_INDEX_SYSTEM_ID)
- && !Groups.GROUP_MY_CONTACTS.equals(systemId)) {
- // All groups that aren't My Contacts, since that one is localized on the phone
-
- // Localize the "Starred in Android" string which we get from the server side.
- if (Groups.GROUP_ANDROID_STARRED.equals(name)) {
- name = getString(R.string.starredInAndroid);
- }
- groups.add(name);
- if (name.equals(mDisplayInfo)) {
- currentIndex = groups.size() - 1;
- }
- } else {
- // The My Contacts group
- groups.add(DISPLAY_GROUP_INDEX_MY_CONTACTS,
- getString(R.string.groupNameMyContacts));
- if (mDisplayType == DISPLAY_TYPE_SYSTEM_GROUP
- && Groups.GROUP_MY_CONTACTS.equals(mDisplayInfo)) {
- currentIndex = DISPLAY_GROUP_INDEX_MY_CONTACTS;
- }
- mDisplayGroupsIncludesMyContacts = true;
- }
- }
- if (mMode == MODE_ALL_CONTACTS) {
- currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS;
- } else if (mMode == MODE_WITH_PHONES) {
- currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES;
- }
- mDisplayGroups = groups.toArray(new CharSequence[groups.size()]);
- builder.setSingleChoiceItems(mDisplayGroups, currentIndex, this);
- mDisplayGroupOriginalSelection = currentIndex;
- } finally {
- cursor.close();
- }
- }
-
- private static final class QueryHandler extends AsyncQueryHandler {
- private final WeakReference<ContactsListActivity> mActivity;
+ private static class QueryHandler extends AsyncQueryHandler {
+ protected final WeakReference<ContactsListActivity> mActivity;
+ protected boolean mLoadingJoinSuggestions = false;
public QueryHandler(Context context) {
super(context.getContentResolver());
mActivity = new WeakReference<ContactsListActivity>((ContactsListActivity) context);
}
+ public void setLoadingJoinSuggestions(boolean flag) {
+ mLoadingJoinSuggestions = flag;
+ }
+
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
final ContactsListActivity activity = mActivity.get();
if (activity != null && !activity.isFinishing()) {
+
+ // Whenever we get a suggestions cursor, we need to immediately kick off
+ // another query for the complete list of contacts
+ if (cursor != null && mLoadingJoinSuggestions) {
+ mLoadingJoinSuggestions = false;
+ if (cursor.getCount() > 0) {
+ activity.mAdapter.setSuggestionsCursor(cursor);
+ } else {
+ cursor.close();
+ activity.mAdapter.setSuggestionsCursor(null);
+ }
+
+ if (activity.mAdapter.mSuggestionsCursorCount == 0
+ || !activity.mJoinModeShowAllContacts) {
+ startQuery(QUERY_TOKEN, null, activity.getContactFilterUri(
+ activity.mQueryData),
+ CONTACTS_SUMMARY_PROJECTION,
+ Contacts._ID + " != " + activity.mQueryAggregateId
+ + " AND " + CLAUSE_ONLY_VISIBLE, null,
+ getSortOrder(CONTACTS_SUMMARY_PROJECTION));
+ return;
+ }
+
+ cursor = activity.getShowAllContactsLabelCursor(CONTACTS_SUMMARY_PROJECTION);
+ }
+
activity.mAdapter.setLoading(false);
- activity.getListView().clearTextFilter();
+ activity.getListView().clearTextFilter();
activity.mAdapter.changeCursor(cursor);
-
+
// Now that the cursor is populated again, it's possible to restore the list state
if (activity.mListState != null) {
activity.mList.onRestoreInstanceState(activity.mListState);
@@ -1633,63 +2028,219 @@
}
final static class ContactListItemCache {
+ public View header;
+ public TextView headerText;
+ public View divider;
public TextView nameView;
+ public View callView;
+ public ImageView callButton;
public CharArrayBuffer nameBuffer = new CharArrayBuffer(128);
public TextView labelView;
public CharArrayBuffer labelBuffer = new CharArrayBuffer(128);
- public TextView numberView;
- public CharArrayBuffer numberBuffer = new CharArrayBuffer(128);
+ public TextView dataView;
+ public CharArrayBuffer dataBuffer = new CharArrayBuffer(128);
public ImageView presenceView;
- public ImageView photoView;
+ public QuickContactBadge photoView;
+ public ImageView nonQuickContactPhotoView;
}
- private final class ContactItemListAdapter extends ResourceCursorAdapter
- implements SectionIndexer {
+ final static class PhotoInfo {
+ public int position;
+ public long photoId;
+
+ public PhotoInfo(int position, long photoId) {
+ this.position = position;
+ this.photoId = photoId;
+ }
+ public QuickContactBadge photoView;
+ }
+
+ private final class ContactItemListAdapter extends ResourceCursorAdapter
+ implements SectionIndexer, OnScrollListener {
private SectionIndexer mIndexer;
private String mAlphabet;
private boolean mLoading = true;
private CharSequence mUnknownNameText;
- private CharSequence[] mLocalizedLabels;
private boolean mDisplayPhotos = false;
- private SparseArray<SoftReference<Bitmap>> mBitmapCache = null;
+ private boolean mDisplayCallButton = false;
+ private boolean mDisplayAdditionalData = true;
+ private HashMap<Long, SoftReference<Bitmap>> mBitmapCache = null;
+ private HashSet<ImageView> mItemsMissingImages = null;
private int mFrequentSeparatorPos = ListView.INVALID_POSITION;
+ private boolean mDisplaySectionHeaders = true;
+ private int[] mSectionPositions;
+ private Cursor mSuggestionsCursor;
+ private int mSuggestionsCursorCount;
+ private ImageFetchHandler mHandler;
+ private ImageDbFetcher mImageFetcher;
+ private static final int FETCH_IMAGE_MSG = 1;
public ContactItemListAdapter(Context context) {
super(context, R.layout.contacts_list_item, null, false);
-
+
+ mHandler = new ImageFetchHandler();
mAlphabet = context.getString(com.android.internal.R.string.fast_scroll_alphabet);
-
+
mUnknownNameText = context.getText(android.R.string.unknownName);
switch (mMode) {
+ case MODE_LEGACY_PICK_POSTAL:
case MODE_PICK_POSTAL:
- mLocalizedLabels = EditContactActivity.getLabelsForKind(mContext,
- Contacts.KIND_POSTAL);
+ mDisplaySectionHeaders = false;
+ break;
+ case MODE_LEGACY_PICK_PHONE:
+ case MODE_PICK_PHONE:
+ mDisplaySectionHeaders = false;
break;
default:
- mLocalizedLabels = EditContactActivity.getLabelsForKind(mContext,
- Contacts.KIND_PHONE);
break;
}
-
+
+ // Do not display the second line of text if in a specific SEARCH query mode, usually for
+ // matching a specific E-mail or phone number. Any contact details
+ // shown would be identical, and columns might not even be present
+ // in the returned cursor.
+ if (mQueryMode != QUERY_MODE_NONE) {
+ mDisplayAdditionalData = false;
+ }
+
+ if ((mMode & MODE_MASK_NO_DATA) == MODE_MASK_NO_DATA) {
+ mDisplayAdditionalData = false;
+ }
+
+ if ((mMode & MODE_MASK_SHOW_CALL_BUTTON) == MODE_MASK_SHOW_CALL_BUTTON) {
+ mDisplayCallButton = true;
+ }
+
if ((mMode & MODE_MASK_SHOW_PHOTOS) == MODE_MASK_SHOW_PHOTOS) {
mDisplayPhotos = true;
setViewResource(R.layout.contacts_list_item_photo);
- mBitmapCache = new SparseArray<SoftReference<Bitmap>>();
+ mBitmapCache = new HashMap<Long, SoftReference<Bitmap>>();
+ mItemsMissingImages = new HashSet<ImageView>();
+ }
+
+ if (mMode == MODE_STREQUENT || mMode == MODE_FREQUENT) {
+ mDisplaySectionHeaders = false;
}
}
- private SectionIndexer getNewIndexer(Cursor cursor) {
- if (Locale.getDefault().getLanguage().equals(Locale.JAPAN.getLanguage())) {
- return new JapaneseContactListIndexer(cursor, SORT_STRING_INDEX);
- } else {
- return new AlphabetIndexer(cursor, NAME_COLUMN_INDEX, mAlphabet);
+ private class ImageFetchHandler extends Handler {
+
+ @Override
+ public void handleMessage(Message message) {
+ if (ContactsListActivity.this.isFinishing()) {
+ return;
+ }
+ switch(message.what) {
+ case FETCH_IMAGE_MSG: {
+ final ImageView imageView = (ImageView) message.obj;
+ if (imageView == null) {
+ break;
+ }
+
+ final PhotoInfo info = (PhotoInfo)imageView.getTag();
+ if (info == null) {
+ break;
+ }
+
+ final long photoId = info.photoId;
+ if (photoId == 0) {
+ break;
+ }
+
+ SoftReference<Bitmap> photoRef = mBitmapCache.get(photoId);
+ if (photoRef == null) {
+ break;
+ }
+ Bitmap photo = photoRef.get();
+ if (photo == null) {
+ mBitmapCache.remove(photoId);
+ break;
+ }
+
+ // Make sure the photoId on this image view has not changed
+ // while we were loading the image.
+ synchronized (imageView) {
+ final PhotoInfo updatedInfo = (PhotoInfo)imageView.getTag();
+ long currentPhotoId = updatedInfo.photoId;
+ if (currentPhotoId == photoId) {
+ imageView.setImageBitmap(photo);
+ mItemsMissingImages.remove(imageView);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ public void clearImageFecthing() {
+ removeMessages(FETCH_IMAGE_MSG);
}
}
-
+
+ private class ImageDbFetcher implements Runnable {
+ long mPhotoId;
+ private ImageView mImageView;
+
+ public ImageDbFetcher(long photoId, ImageView imageView) {
+ this.mPhotoId = photoId;
+ this.mImageView = imageView;
+ }
+
+ public void run() {
+ if (ContactsListActivity.this.isFinishing()) {
+ return;
+ }
+
+ if (Thread.currentThread().interrupted()) {
+ // shutdown has been called.
+ return;
+ }
+ Bitmap photo = null;
+ try {
+ photo = ContactsUtils.loadContactPhoto(mContext, mPhotoId, null);
+ } catch (OutOfMemoryError e) {
+ // Not enough memory for the photo, do nothing.
+ }
+
+ if (photo == null) {
+ return;
+ }
+
+ mBitmapCache.put(mPhotoId, new SoftReference<Bitmap>(photo));
+
+ if (Thread.currentThread().interrupted()) {
+ // shutdown has been called.
+ return;
+ }
+
+ // Update must happen on UI thread
+ Message msg = new Message();
+ msg.what = FETCH_IMAGE_MSG;
+ msg.obj = mImageView;
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ public void setSuggestionsCursor(Cursor cursor) {
+ if (mSuggestionsCursor != null) {
+ mSuggestionsCursor.close();
+ }
+ mSuggestionsCursor = cursor;
+ mSuggestionsCursorCount = cursor == null ? 0 : cursor.getCount();
+ }
+
+ private SectionIndexer getNewIndexer(Cursor cursor) {
+ /* if (Locale.getDefault().getLanguage().equals(Locale.JAPAN.getLanguage())) {
+ return new JapaneseContactListIndexer(cursor, SORT_STRING_INDEX);
+ } else { */
+ return new AlphabetIndexer(cursor, SUMMARY_NAME_COLUMN_INDEX, mAlphabet);
+ /* } */
+ }
+
/**
* Callback on the UI thread when the content observer on the backing cursor fires.
* Instead of calling requery we need to do an async query so that the requery doesn't
- * block the UI thread for a long time.
+ * block the UI thread for a long time.
*/
@Override
protected void onContentChanged() {
@@ -1703,7 +2254,7 @@
startQuery();
}
}
-
+
public void setLoading(boolean loading) {
mLoading = loading;
}
@@ -1726,7 +2277,13 @@
@Override
public int getItemViewType(int position) {
- if (position == mFrequentSeparatorPos) {
+ if (position == 0 && (mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ return IGNORE_ITEM_VIEW_TYPE;
+ }
+ if (isShowAllContactsItemPosition(position)) {
+ return IGNORE_ITEM_VIEW_TYPE;
+ }
+ if (getSeparatorId(position) != 0) {
// We don't want the separator view to be recycled.
return IGNORE_ITEM_VIEW_TYPE;
}
@@ -1740,39 +2297,126 @@
"this should only be called when the cursor is valid");
}
- // Handle the separator specially
- if (position == mFrequentSeparatorPos) {
+ // handle the total contacts item
+ if (position == 0 && (mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ return getTotalContactCountView(parent);
+ }
+
+ if (isShowAllContactsItemPosition(position)) {
LayoutInflater inflater =
- (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ return inflater.inflate(R.layout.contacts_list_show_all_item, parent, false);
+ }
+
+ // Handle the separator specially
+ int separatorId = getSeparatorId(position);
+ if (separatorId != 0) {
+ LayoutInflater inflater =
+ (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
TextView view = (TextView) inflater.inflate(R.layout.list_separator, parent, false);
- view.setText(R.string.favoritesFrquentSeparator);
+ view.setText(separatorId);
return view;
}
- if (!mCursor.moveToPosition(getRealPosition(position))) {
+ boolean showingSuggestion;
+ Cursor cursor;
+ if (mSuggestionsCursorCount != 0 && position < mSuggestionsCursorCount + 2) {
+ showingSuggestion = true;
+ cursor = mSuggestionsCursor;
+ } else {
+ showingSuggestion = false;
+ cursor = mCursor;
+ }
+
+ int realPosition = getRealPosition(position);
+ if (!cursor.moveToPosition(realPosition)) {
throw new IllegalStateException("couldn't move cursor to position " + position);
}
-
+
View v;
if (convertView == null) {
- v = newView(mContext, mCursor, parent);
+ v = newView(mContext, cursor, parent);
} else {
v = convertView;
}
- bindView(v, mContext, mCursor);
+ bindView(v, mContext, cursor);
+ bindSectionHeader(v, realPosition, mDisplaySectionHeaders && !showingSuggestion);
return v;
}
+ private View getTotalContactCountView(ViewGroup parent) {
+ final LayoutInflater inflater = getLayoutInflater();
+ TextView totalContacts = (TextView) inflater.inflate(R.layout.total_contacts,
+ parent, false);
+
+ String text;
+ int count = getRealCount();
+
+ if (mMode == MODE_QUERY || !TextUtils.isEmpty(getListView().getTextFilter())) {
+ text = getQuantityText(count, R.string.listFoundAllContactsZero,
+ R.plurals.listFoundAllContacts);
+ } else {
+ if (mDisplayOnlyPhones) {
+ text = getQuantityText(count, R.string.listTotalPhoneContactsZero,
+ R.plurals.listTotalPhoneContacts);
+ } else {
+ text = getQuantityText(count, R.string.listTotalAllContactsZero,
+ R.plurals.listTotalAllContacts);
+ }
+ }
+ totalContacts.setText(text);
+ return totalContacts;
+ }
+
+ // TODO: fix PluralRules to handle zero correctly and use Resources.getQuantityText directly
+ private String getQuantityText(int count, int zeroResourceId, int pluralResourceId) {
+ if (count == 0) {
+ return getString(zeroResourceId);
+ } else {
+ String format = getResources().getQuantityText(pluralResourceId, count).toString();
+ return String.format(format, count);
+ }
+ }
+
+ private boolean isShowAllContactsItemPosition(int position) {
+ return mMode == MODE_JOIN_CONTACT && mJoinModeShowAllContacts
+ && mSuggestionsCursorCount != 0 && position == mSuggestionsCursorCount + 2;
+ }
+
+ private int getSeparatorId(int position) {
+ int separatorId = 0;
+ if (position == mFrequentSeparatorPos) {
+ separatorId = R.string.favoritesFrquentSeparator;
+ }
+ if (mSuggestionsCursorCount != 0) {
+ if (position == 0) {
+ separatorId = R.string.separatorJoinAggregateSuggestions;
+ } else if (position == mSuggestionsCursorCount + 1) {
+ separatorId = R.string.separatorJoinAggregateAll;
+ }
+ }
+ return separatorId;
+ }
+
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final View view = super.newView(context, cursor, parent);
final ContactListItemCache cache = new ContactListItemCache();
+ cache.header = view.findViewById(R.id.header);
+ cache.headerText = (TextView)view.findViewById(R.id.header_text);
+ cache.divider = view.findViewById(R.id.list_divider);
cache.nameView = (TextView) view.findViewById(R.id.name);
+ cache.callView = view.findViewById(R.id.call_view);
+ cache.callButton = (ImageView) view.findViewById(R.id.call_button);
+ if (cache.callButton != null) {
+ cache.callButton.setOnClickListener(ContactsListActivity.this);
+ }
cache.labelView = (TextView) view.findViewById(R.id.label);
- cache.numberView = (TextView) view.findViewById(R.id.number);
+ cache.dataView = (TextView) view.findViewById(R.id.data);
cache.presenceView = (ImageView) view.findViewById(R.id.presence);
- cache.photoView = (ImageView) view.findViewById(R.id.photo);
+ cache.photoView = (QuickContactBadge) view.findViewById(R.id.photo);
+ cache.nonQuickContactPhotoView = (ImageView) view.findViewById(R.id.noQuickContactPhoto);
view.setTag(cache);
return view;
@@ -1781,67 +2425,130 @@
@Override
public void bindView(View view, Context context, Cursor cursor) {
final ContactListItemCache cache = (ContactListItemCache) view.getTag();
-
- // Set the name
- cursor.copyStringToBuffer(NAME_COLUMN_INDEX, cache.nameBuffer);
+
+ TextView dataView = cache.dataView;
+ TextView labelView = cache.labelView;
+ int typeColumnIndex;
+ int dataColumnIndex;
+ int labelColumnIndex;
+ int defaultType;
+ int nameColumnIndex;
+ boolean displayAdditionalData = mDisplayAdditionalData;
+ switch(mMode) {
+ case MODE_PICK_PHONE:
+ case MODE_LEGACY_PICK_PHONE: {
+ nameColumnIndex = PHONE_DISPLAY_NAME_COLUMN_INDEX;
+ dataColumnIndex = PHONE_NUMBER_COLUMN_INDEX;
+ typeColumnIndex = PHONE_TYPE_COLUMN_INDEX;
+ labelColumnIndex = PHONE_LABEL_COLUMN_INDEX;
+ defaultType = Phone.TYPE_HOME;
+ break;
+ }
+ case MODE_PICK_POSTAL:
+ case MODE_LEGACY_PICK_POSTAL: {
+ nameColumnIndex = POSTAL_DISPLAY_NAME_COLUMN_INDEX;
+ dataColumnIndex = POSTAL_ADDRESS_COLUMN_INDEX;
+ typeColumnIndex = POSTAL_TYPE_COLUMN_INDEX;
+ labelColumnIndex = POSTAL_LABEL_COLUMN_INDEX;
+ defaultType = StructuredPostal.TYPE_HOME;
+ break;
+ }
+ default: {
+ nameColumnIndex = SUMMARY_NAME_COLUMN_INDEX;
+ dataColumnIndex = -1;
+ typeColumnIndex = -1;
+ labelColumnIndex = -1;
+ defaultType = Phone.TYPE_HOME;
+ displayAdditionalData = false;
+ }
+ }
+
+ // Set the name
+ cursor.copyStringToBuffer(nameColumnIndex, cache.nameBuffer);
int size = cache.nameBuffer.sizeCopied;
if (size != 0) {
cache.nameView.setText(cache.nameBuffer.data, 0, size);
} else {
cache.nameView.setText(mUnknownNameText);
}
-
- // Bail out early if using a specific SEARCH query mode, usually for
- // matching a specific E-mail or phone number. Any contact details
- // shown would be identical, and columns might not even be present
- // in the returned cursor.
- if (mQueryMode != QUERY_MODE_NONE) {
- cache.numberView.setVisibility(View.GONE);
- cache.labelView.setVisibility(View.GONE);
- cache.presenceView.setVisibility(View.GONE);
- return;
- }
-
- // Set the phone number
- TextView numberView = cache.numberView;
- TextView labelView = cache.labelView;
- cursor.copyStringToBuffer(NUMBER_COLUMN_INDEX, cache.numberBuffer);
- size = cache.numberBuffer.sizeCopied;
- if (size != 0) {
- numberView.setText(cache.numberBuffer.data, 0, size);
- numberView.setVisibility(View.VISIBLE);
- labelView.setVisibility(View.VISIBLE);
+
+ // Make the call button visible if requested.
+ if (mDisplayCallButton) {
+ int pos = cursor.getPosition();
+ cache.callView.setVisibility(View.VISIBLE);
+ cache.callButton.setTag(pos);
} else {
- numberView.setVisibility(View.GONE);
- labelView.setVisibility(View.GONE);
+ cache.callView.setVisibility(View.GONE);
}
- // Set the label
- if (!cursor.isNull(TYPE_COLUMN_INDEX)) {
- int type = cursor.getInt(TYPE_COLUMN_INDEX);
+ // Set the photo, if requested
+ if (mDisplayPhotos) {
+ boolean useQuickContact = (mMode & MODE_MASK_DISABLE_QUIKCCONTACT) == 0;
- if (type != People.Phones.TYPE_CUSTOM) {
- try {
- labelView.setText(mLocalizedLabels[type - 1]);
- } catch (ArrayIndexOutOfBoundsException e) {
- labelView.setText(mLocalizedLabels[People.Phones.TYPE_HOME - 1]);
- }
- } else {
- cursor.copyStringToBuffer(LABEL_COLUMN_INDEX, cache.labelBuffer);
- // Don't check size, if it's zero just don't show anything
- labelView.setText(cache.labelBuffer.data, 0, cache.labelBuffer.sizeCopied);
+ long photoId = 0;
+ if (!cursor.isNull(SUMMARY_PHOTO_ID_COLUMN_INDEX)) {
+ photoId = cursor.getLong(SUMMARY_PHOTO_ID_COLUMN_INDEX);
}
- } else {
- // There is no label, hide the the view
- labelView.setVisibility(View.GONE);
+
+ ImageView viewToUse;
+ if (useQuickContact) {
+ viewToUse = cache.photoView;
+ // Build soft lookup reference
+ final long contactId = cursor.getLong(SUMMARY_ID_COLUMN_INDEX);
+ final String lookupKey = cursor.getString(SUMMARY_LOOKUP_KEY);
+ cache.photoView.assignContactUri(Contacts.getLookupUri(contactId, lookupKey));
+ cache.photoView.setVisibility(View.VISIBLE);
+ cache.nonQuickContactPhotoView.setVisibility(View.INVISIBLE);
+ } else {
+ viewToUse = cache.nonQuickContactPhotoView;
+ cache.photoView.setVisibility(View.INVISIBLE);
+ cache.nonQuickContactPhotoView.setVisibility(View.VISIBLE);
+ }
+
+
+ final int position = cursor.getPosition();
+ viewToUse.setTag(new PhotoInfo(position, photoId));
+
+ if (photoId == 0) {
+ viewToUse.setImageResource(R.drawable.ic_contact_list_picture);
+ } else {
+
+ Bitmap photo = null;
+
+ // Look for the cached bitmap
+ SoftReference<Bitmap> ref = mBitmapCache.get(photoId);
+ if (ref != null) {
+ photo = ref.get();
+ if (photo == null) {
+ mBitmapCache.remove(photoId);
+ }
+ }
+
+ // Bind the photo, or use the fallback no photo resource
+ if (photo != null) {
+ viewToUse.setImageBitmap(photo);
+ } else {
+ // Cache miss
+ viewToUse.setImageResource(R.drawable.ic_contact_list_picture);
+
+ // Add it to a set of images that are populated asynchronously.
+ mItemsMissingImages.add(viewToUse);
+
+ if (mScrollState != OnScrollListener.SCROLL_STATE_FLING) {
+
+ // Scrolling is idle or slow, go get the image right now.
+ sendFetchImageMessage(viewToUse);
+ }
+ }
+ }
}
- // Set the proper icon (star or presence or nothing)
ImageView presenceView = cache.presenceView;
if ((mMode & MODE_MASK_NO_PRESENCE) == 0) {
+ // Set the proper icon (star or presence or nothing)
int serverStatus;
- if (!cursor.isNull(SERVER_STATUS_COLUMN_INDEX)) {
- serverStatus = cursor.getInt(SERVER_STATUS_COLUMN_INDEX);
+ if (!cursor.isNull(SUMMARY_PRESENCE_STATUS_COLUMN_INDEX)) {
+ serverStatus = cursor.getInt(SUMMARY_PRESENCE_STATUS_COLUMN_INDEX);
presenceView.setImageResource(
Presence.getPresenceIconResourceId(serverStatus));
presenceView.setVisibility(View.VISIBLE);
@@ -1852,49 +2559,81 @@
presenceView.setVisibility(View.GONE);
}
- // Set the photo, if requested
- if (mDisplayPhotos) {
- Bitmap photo = null;
+ if (!displayAdditionalData) {
+ cache.dataView.setVisibility(View.GONE);
+ cache.labelView.setVisibility(View.GONE);
+ return;
+ }
- // Look for the cached bitmap
- int pos = cursor.getPosition();
- SoftReference<Bitmap> ref = mBitmapCache.get(pos);
- if (ref != null) {
- photo = ref.get();
- }
+ // Set the data.
+ cursor.copyStringToBuffer(dataColumnIndex, cache.dataBuffer);
- if (photo == null) {
- // Bitmap cache miss, decode it from the cursor
- if (!cursor.isNull(PHOTO_COLUMN_INDEX)) {
- try {
- byte[] photoData = cursor.getBlob(PHOTO_COLUMN_INDEX);
- photo = BitmapFactory.decodeByteArray(photoData, 0,
- photoData.length);
- mBitmapCache.put(pos, new SoftReference<Bitmap>(photo));
- } catch (OutOfMemoryError e) {
- // Not enough memory for the photo, use the default one instead
- photo = null;
- }
- }
- }
+ size = cache.dataBuffer.sizeCopied;
+ if (size != 0) {
+ dataView.setText(cache.dataBuffer.data, 0, size);
+ dataView.setVisibility(View.VISIBLE);
+ } else {
+ dataView.setVisibility(View.GONE);
+ }
- // Bind the photo, or use the fallback no photo resource
- if (photo != null) {
- cache.photoView.setImageBitmap(photo);
+ // Set the label.
+ if (!cursor.isNull(typeColumnIndex)) {
+ labelView.setVisibility(View.VISIBLE);
+
+ final int type = cursor.getInt(typeColumnIndex);
+ final String label = cursor.getString(labelColumnIndex);
+
+ if (mMode == MODE_LEGACY_PICK_POSTAL || mMode == MODE_PICK_POSTAL) {
+ labelView.setText(StructuredPostal.getTypeLabel(context.getResources(), type,
+ label));
} else {
- cache.photoView.setImageResource(R.drawable.ic_contact_list_picture);
+ labelView.setText(Phone.getTypeLabel(context.getResources(), type, label));
+ }
+ } else {
+ // There is no label, hide the the view
+ labelView.setVisibility(View.GONE);
+ }
+ }
+
+ private void bindSectionHeader(View view, int position, boolean displaySectionHeaders) {
+ final ContactListItemCache cache = (ContactListItemCache) view.getTag();
+ if (!displaySectionHeaders) {
+ cache.header.setVisibility(View.GONE);
+ cache.divider.setVisibility(View.VISIBLE);
+ } else {
+ final int section = getSectionForPosition(position);
+ if (getPositionForSection(section) == position) {
+ String title = mIndexer.getSections()[section].toString().trim();
+ if (!TextUtils.isEmpty(title)) {
+ cache.headerText.setText(title);
+ cache.header.setVisibility(View.VISIBLE);
+ } else {
+ cache.header.setVisibility(View.GONE);
+ }
+ } else {
+ cache.header.setVisibility(View.GONE);
+ }
+
+ // move the divider for the last item in a section
+ if (getPositionForSection(section + 1) - 1 == position) {
+ cache.divider.setVisibility(View.GONE);
+ } else {
+ cache.divider.setVisibility(View.VISIBLE);
}
}
}
@Override
public void changeCursor(Cursor cursor) {
+
// Get the split between starred and frequent items, if the mode is strequent
mFrequentSeparatorPos = ListView.INVALID_POSITION;
- if (cursor != null && cursor.getCount() > 0 && mMode == MODE_STREQUENT) {
+ int cursorCount = 0;
+ if (cursor != null && (cursorCount = cursor.getCount()) > 0
+ && mMode == MODE_STREQUENT) {
cursor.move(-1);
for (int i = 0; cursor.moveToNext(); i++) {
- int starred = cursor.getInt(STARRED_COLUMN_INDEX);
+ int starred = cursor.getInt(SUMMARY_STARRED_COLUMN_INDEX);
if (starred == 0) {
if (i > 0) {
// Only add the separator when there are starred items present
@@ -1906,16 +2645,10 @@
}
super.changeCursor(cursor);
-
// Update the indexer for the fast scroll widget
updateIndexer(cursor);
-
- // Clear the photo bitmap cache, if there is one
- if (mBitmapCache != null) {
- mBitmapCache.clear();
- }
}
-
+
private void updateIndexer(Cursor cursor) {
if (mIndexer == null) {
mIndexer = getNewIndexer(cursor);
@@ -1934,8 +2667,16 @@
}
}
}
+
+ int sectionCount = mIndexer.getSections().length;
+ if (mSectionPositions == null || mSectionPositions.length != sectionCount) {
+ mSectionPositions = new int[sectionCount];
+ }
+ for (int i = 0; i < sectionCount; i++) {
+ mSectionPositions[i] = ListView.INVALID_POSITION;
+ }
}
-
+
/**
* Run the query on a helper thread. Beware that this code does not run
* on the main UI thread!
@@ -1944,18 +2685,22 @@
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
return doFilter(constraint.toString());
}
-
+
public Object [] getSections() {
- if (mMode == MODE_STREQUENT) {
+ if (mMode == MODE_STARRED) {
return new String[] { " " };
} else {
return mIndexer.getSections();
- }
+ }
}
public int getPositionForSection(int sectionIndex) {
- if (mMode == MODE_STREQUENT) {
- return 0;
+ if (mMode == MODE_STARRED) {
+ return -1;
+ }
+
+ if (sectionIndex < 0 || sectionIndex >= mSectionPositions.length) {
+ return -1;
}
if (mIndexer == null) {
@@ -1967,37 +2712,113 @@
mIndexer = getNewIndexer(cursor);
}
- return mIndexer.getPositionForSection(sectionIndex);
+ int position = mSectionPositions[sectionIndex];
+ if (position == ListView.INVALID_POSITION) {
+ position = mSectionPositions[sectionIndex] =
+ mIndexer.getPositionForSection(sectionIndex);
+ }
+
+ return position;
}
public int getSectionForPosition(int position) {
- // Note: JapaneseContactListIndexer depends on the fact
- // this method always returns 0. If you change this,
- // please care it too.
- return 0;
+ // The current implementations of SectionIndexers (specifically the Japanese indexer)
+ // only work in one direction: given a section they can calculate the position.
+ // Here we are using that existing functionality to do the reverse mapping. We are
+ // performing binary search in the mSectionPositions array, which itself is populated
+ // lazily using the "forward" mapping supported by the indexer.
+
+ int start = 0;
+ int end = mSectionPositions.length;
+ while (start != end) {
+
+ // We are making the binary search slightly asymmetrical, because the
+ // user is more likely to be scrolling the list from the top down.
+ int pivot = start + (end - start) / 4;
+
+ int value = getPositionForSection(pivot);
+ if (value <= position) {
+ start = pivot + 1;
+ } else {
+ end = pivot;
+ }
+ }
+
+ // The variable "start" cannot be 0, as long as the indexer is implemented properly
+ // and actually maps position = 0 to section = 0
+ return start - 1;
}
@Override
public boolean areAllItemsEnabled() {
- return mMode != MODE_STREQUENT;
+ return mMode != MODE_STARRED
+ && (mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) == 0
+ && mSuggestionsCursorCount == 0;
}
@Override
public boolean isEnabled(int position) {
+ if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ if (position == 0) {
+ return false;
+ }
+ position--;
+ }
+
+ if (mSuggestionsCursorCount > 0) {
+ return position != 0 && position != mSuggestionsCursorCount + 1;
+ }
return position != mFrequentSeparatorPos;
}
@Override
public int getCount() {
- if (mFrequentSeparatorPos != ListView.INVALID_POSITION) {
- return super.getCount() + 1;
+ if (!mDataValid) {
+ return 0;
+ }
+ int superCount = super.getCount();
+ if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0 && superCount > 0) {
+ // We don't want to count this header if it's the only thing visible, so that
+ // the empty text will display.
+ superCount++;
+ }
+ if (mSuggestionsCursorCount != 0) {
+ // When showing suggestions, we have 2 additional list items: the "Suggestions"
+ // and "All contacts" headers.
+ return mSuggestionsCursorCount + superCount + 2;
+ }
+ else if (mFrequentSeparatorPos != ListView.INVALID_POSITION) {
+ // When showing strequent list, we have an additional list item - the separator.
+ return superCount + 1;
} else {
- return super.getCount();
+ return superCount;
}
}
-
+
+ /**
+ * Gets the actual count of contacts and excludes all the headers.
+ */
+ public int getRealCount() {
+ return super.getCount();
+ }
+
private int getRealPosition(int pos) {
- if (mFrequentSeparatorPos == ListView.INVALID_POSITION) {
+ if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ pos--;
+ }
+ if (mSuggestionsCursorCount != 0) {
+ // When showing suggestions, we have 2 additional list items: the "Suggestions"
+ // and "All contacts" separators.
+ if (pos < mSuggestionsCursorCount + 2) {
+ // We are in the upper partition (Suggestions). Adjusting for the "Suggestions"
+ // separator.
+ return pos - 1;
+ } else {
+ // We are in the lower partition (All contacts). Adjusting for the size
+ // of the upper partition plus the two separators.
+ return pos - mSuggestionsCursorCount - 2;
+ }
+ } else if (mFrequentSeparatorPos == ListView.INVALID_POSITION) {
// No separator, identity map
return pos;
} else if (pos <= mFrequentSeparatorPos) {
@@ -2007,17 +2828,89 @@
// After the separator, remove 1 from the pos to get the real underlying pos
return pos - 1;
}
-
}
-
+
@Override
public Object getItem(int pos) {
- return super.getItem(getRealPosition(pos));
+ if (mSuggestionsCursorCount != 0 && pos <= mSuggestionsCursorCount) {
+ mSuggestionsCursor.moveToPosition(getRealPosition(pos));
+ return mSuggestionsCursor;
+ } else {
+ return super.getItem(getRealPosition(pos));
+ }
}
-
+
@Override
public long getItemId(int pos) {
- return super.getItemId(getRealPosition(pos));
+ if (mSuggestionsCursorCount != 0 && pos < mSuggestionsCursorCount + 2) {
+ if (mSuggestionsCursor.moveToPosition(pos - 1)) {
+ return mSuggestionsCursor.getLong(mRowIDColumn);
+ } else {
+ return 0;
+ }
+ }
+ return super.getItemId(getRealPosition(pos));
+ }
+
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+ int totalItemCount) {
+ // no op
+ }
+
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ mScrollState = scrollState;
+ if (scrollState == OnScrollListener.SCROLL_STATE_FLING) {
+ // If we are in a fling, stop loading images.
+ clearImageFetching();
+ } else if (mDisplayPhotos) {
+ processMissingImageItems(view);
+ }
+ }
+
+ private void processMissingImageItems(AbsListView view) {
+ for (ImageView iv : mItemsMissingImages) {
+ sendFetchImageMessage(iv);
+ }
+ }
+
+ private void sendFetchImageMessage(ImageView view) {
+ final PhotoInfo info = (PhotoInfo) view.getTag();
+ if (info == null) {
+ return;
+ }
+ final long photoId = info.photoId;
+ if (photoId == 0) {
+ return;
+ }
+ mImageFetcher = new ImageDbFetcher(photoId, view);
+ synchronized (ContactsListActivity.this) {
+ // can't sync on sImageFetchThreadPool.
+ if (sImageFetchThreadPool == null) {
+ // Don't use more than 3 threads at a time to update. The thread pool will be
+ // shared by all contact items.
+ sImageFetchThreadPool = Executors.newFixedThreadPool(3);
+ }
+ sImageFetchThreadPool.execute(mImageFetcher);
+ }
+ }
+
+
+ /**
+ * Stop the image fetching for ALL contacts, if one is in progress we'll
+ * not query the database.
+ *
+ * TODO: move this method to ContactsListActivity, it does not apply to the current
+ * contact.
+ */
+ public void clearImageFetching() {
+ synchronized (ContactsListActivity.this) {
+ if (sImageFetchThreadPool != null) {
+ sImageFetchThreadPool.shutdownNow();
+ sImageFetchThreadPool = null;
+ }
+ }
+
+ mHandler.clearImageFecthing();
}
}
}
diff --git a/src/com/android/contacts/ContactsLiveFolders.java b/src/com/android/contacts/ContactsLiveFolders.java
index d437e80..64be0e2 100644
--- a/src/com/android/contacts/ContactsLiveFolders.java
+++ b/src/com/android/contacts/ContactsLiveFolders.java
@@ -16,13 +16,13 @@
package com.android.contacts;
-import android.content.Intent;
-import android.content.Context;
-import android.net.Uri;
import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
+import android.provider.ContactsContract.Contacts;
import android.provider.LiveFolders;
-import android.provider.Contacts;
public class ContactsLiveFolders {
public static class StarredContacts extends Activity {
@@ -100,8 +100,8 @@
final Intent intent = new Intent();
intent.setData(uri);
- intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT, new Intent(Intent.ACTION_VIEW,
- Contacts.People.CONTENT_URI));
+ intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT,
+ new Intent(Intent.ACTION_VIEW, Contacts.CONTENT_URI));
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,
Intent.ShortcutIconResource.fromContext(context, icon));
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
new file mode 100644
index 0000000..1e3b8ad
--- /dev/null
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -0,0 +1,427 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.Im.ProviderNames;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.util.Constants;
+
+import java.util.ArrayList;
+
+public class ContactsUtils {
+
+ private static final String TAG = "ContactsUtils";
+ /**
+ * Build the display title for the {@link Data#CONTENT_URI} entry in the
+ * provided cursor, assuming the given mimeType.
+ */
+ public static final CharSequence getDisplayLabel(Context context,
+ String mimeType, Cursor cursor) {
+ // Try finding the type and label for this mimetype
+ int colType;
+ int colLabel;
+
+ if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
+ || Constants.MIME_SMS_ADDRESS.equals(mimeType)) {
+ // Reset to phone mimetype so we generate a label for SMS case
+ mimeType = Phone.CONTENT_ITEM_TYPE;
+ colType = cursor.getColumnIndex(Phone.TYPE);
+ colLabel = cursor.getColumnIndex(Phone.LABEL);
+ } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ colType = cursor.getColumnIndex(Email.TYPE);
+ colLabel = cursor.getColumnIndex(Email.LABEL);
+ } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ colType = cursor.getColumnIndex(StructuredPostal.TYPE);
+ colLabel = cursor.getColumnIndex(StructuredPostal.LABEL);
+ } else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ colType = cursor.getColumnIndex(Organization.TYPE);
+ colLabel = cursor.getColumnIndex(Organization.LABEL);
+ } else {
+ return null;
+ }
+
+ final int type = cursor.getInt(colType);
+ final CharSequence label = cursor.getString(colLabel);
+
+ return getDisplayLabel(context, mimeType, type, label);
+ }
+
+ public static final CharSequence getDisplayLabel(Context context, String mimetype, int type,
+ CharSequence label) {
+ CharSequence display = "";
+ final int customType;
+ final int defaultType;
+ final int arrayResId;
+
+ if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ defaultType = Phone.TYPE_HOME;
+ customType = Phone.TYPE_CUSTOM;
+ arrayResId = com.android.internal.R.array.phoneTypes;
+ } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ defaultType = Email.TYPE_HOME;
+ customType = Email.TYPE_CUSTOM;
+ arrayResId = com.android.internal.R.array.emailAddressTypes;
+ } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ defaultType = StructuredPostal.TYPE_HOME;
+ customType = StructuredPostal.TYPE_CUSTOM;
+ arrayResId = com.android.internal.R.array.postalAddressTypes;
+ } else if (Organization.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ defaultType = Organization.TYPE_WORK;
+ customType = Organization.TYPE_CUSTOM;
+ arrayResId = com.android.internal.R.array.organizationTypes;
+ } else {
+ // Can't return display label for given mimetype.
+ return display;
+ }
+
+ if (type != customType) {
+ CharSequence[] labels = context.getResources().getTextArray(arrayResId);
+ try {
+ display = labels[type - 1];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ display = labels[defaultType - 1];
+ }
+ } else {
+ if (!TextUtils.isEmpty(label)) {
+ display = label;
+ }
+ }
+ return display;
+ }
+
+ /**
+ * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
+ * If the person's photo isn't present returns null.
+ *
+ * @param aggCursor the Cursor pointing to the data record containing the photo.
+ * @param bitmapColumnIndex the column index where the photo Uri is stored.
+ * @param options the decoding options, can be set to null
+ * @return the photo Bitmap
+ */
+ public static Bitmap loadContactPhoto(Cursor cursor, int bitmapColumnIndex,
+ BitmapFactory.Options options) {
+ if (cursor == null) {
+ return null;
+ }
+
+ byte[] data = cursor.getBlob(bitmapColumnIndex);
+ return BitmapFactory.decodeByteArray(data, 0, data.length, options);
+ }
+
+ /**
+ * Loads a placeholder photo.
+ *
+ * @param placeholderImageResource the resource to use for the placeholder image
+ * @param context the Context
+ * @param options the decoding options, can be set to null
+ * @return the placeholder Bitmap.
+ */
+ public static Bitmap loadPlaceholderPhoto(int placeholderImageResource, Context context,
+ BitmapFactory.Options options) {
+ if (placeholderImageResource == 0) {
+ return null;
+ }
+ return BitmapFactory.decodeResource(context.getResources(),
+ placeholderImageResource, options);
+ }
+
+ public static Bitmap loadContactPhoto(Context context, long photoId,
+ BitmapFactory.Options options) {
+ Cursor photoCursor = null;
+ Bitmap photoBm = null;
+
+ try {
+ photoCursor = context.getContentResolver().query(
+ ContentUris.withAppendedId(Data.CONTENT_URI, photoId),
+ new String[] { Photo.PHOTO },
+ null, null, null);
+
+ if (photoCursor.moveToFirst() && !photoCursor.isNull(0)) {
+ byte[] photoData = photoCursor.getBlob(0);
+ photoBm = BitmapFactory.decodeByteArray(photoData, 0,
+ photoData.length, options);
+ }
+ } finally {
+ if (photoCursor != null) {
+ photoCursor.close();
+ }
+ }
+
+ return photoBm;
+ }
+
+ /**
+ * This looks up the provider name defined in
+ * {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
+ * This is used for interacting with the IM application.
+ *
+ * @param protocol the protocol ID
+ * @return the provider name the IM app uses for the given protocol, or null if no
+ * provider is defined for the given protocol
+ * @hide
+ */
+ public static String lookupProviderNameFromId(int protocol) {
+ switch (protocol) {
+ case Im.PROTOCOL_GOOGLE_TALK:
+ return ProviderNames.GTALK;
+ case Im.PROTOCOL_AIM:
+ return ProviderNames.AIM;
+ case Im.PROTOCOL_MSN:
+ return ProviderNames.MSN;
+ case Im.PROTOCOL_YAHOO:
+ return ProviderNames.YAHOO;
+ case Im.PROTOCOL_ICQ:
+ return ProviderNames.ICQ;
+ case Im.PROTOCOL_JABBER:
+ return ProviderNames.JABBER;
+ case Im.PROTOCOL_SKYPE:
+ return ProviderNames.SKYPE;
+ case Im.PROTOCOL_QQ:
+ return ProviderNames.QQ;
+ }
+ return null;
+ }
+
+ /**
+ * Build {@link Intent} to launch an action for the given {@link Im} or
+ * {@link Email} row. Returns null when missing protocol or data.
+ */
+ public static Intent buildImIntent(ContentValues values) {
+ final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(values.getAsString(Data.MIMETYPE));
+
+ if (!isEmail && !isProtocolValid(values)) {
+ return null;
+ }
+
+ final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : values.getAsInteger(Im.PROTOCOL);
+
+ String host = values.getAsString(Im.CUSTOM_PROTOCOL);
+ String data = values.getAsString(isEmail ? Email.DATA : Im.DATA);
+ if (protocol != Im.PROTOCOL_CUSTOM) {
+ // Try bringing in a well-known host for specific protocols
+ host = ContactsUtils.lookupProviderNameFromId(protocol);
+ }
+
+ if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(data)) {
+ final String authority = host.toLowerCase();
+ final Uri imUri = new Uri.Builder().scheme(Constants.SCHEME_IMTO).authority(
+ authority).appendPath(data).build();
+ return new Intent(Intent.ACTION_SENDTO, imUri);
+ } else {
+ return null;
+ }
+ }
+
+ private static boolean isProtocolValid(ContentValues values) {
+ String protocolString = values.getAsString(Im.PROTOCOL);
+ if (protocolString == null) {
+ return false;
+ }
+ try {
+ Integer.valueOf(protocolString);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return true;
+ }
+
+ public static Intent getPhotoPickIntent() {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
+ intent.setType("image/*");
+ intent.putExtra("crop", "true");
+ intent.putExtra("aspectX", 1);
+ intent.putExtra("aspectY", 1);
+ intent.putExtra("outputX", 96);
+ intent.putExtra("outputY", 96);
+ intent.putExtra("return-data", true);
+ return intent;
+ }
+
+ public static long queryForContactId(ContentResolver cr, long rawContactId) {
+ Cursor contactIdCursor = null;
+ long contactId = -1;
+ try {
+ contactIdCursor = cr.query(RawContacts.CONTENT_URI,
+ new String[] {RawContacts.CONTACT_ID},
+ RawContacts._ID + "=" + rawContactId, null, null);
+ if (contactIdCursor != null && contactIdCursor.moveToFirst()) {
+ contactId = contactIdCursor.getLong(0);
+ }
+ } finally {
+ if (contactIdCursor != null) {
+ contactIdCursor.close();
+ }
+ }
+ return contactId;
+ }
+
+ public static String querySuperPrimaryPhone(ContentResolver cr, long contactId) {
+ Cursor c = null;
+ String phone = null;
+ try {
+ Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+ Uri dataUri = Uri.withAppendedPath(baseUri, Contacts.Data.CONTENT_DIRECTORY);
+
+ c = cr.query(dataUri,
+ new String[] {Phone.NUMBER},
+ Data.MIMETYPE + "=" + Phone.MIMETYPE +
+ " AND " + Data.IS_SUPER_PRIMARY + "=1",
+ null, null);
+ if (c != null && c.moveToFirst()) {
+ // Just return the first one.
+ phone = c.getString(0);
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ return phone;
+ }
+
+ public static long queryForRawContactId(ContentResolver cr, long contactId) {
+ Cursor rawContactIdCursor = null;
+ long rawContactId = -1;
+ try {
+ rawContactIdCursor = cr.query(RawContacts.CONTENT_URI,
+ new String[] {RawContacts._ID},
+ RawContacts.CONTACT_ID + "=" + contactId, null, null);
+ if (rawContactIdCursor != null && rawContactIdCursor.moveToFirst()) {
+ // Just return the first one.
+ rawContactId = rawContactIdCursor.getLong(0);
+ }
+ } finally {
+ if (rawContactIdCursor != null) {
+ rawContactIdCursor.close();
+ }
+ }
+ return rawContactId;
+ }
+
+ public static ArrayList<Long> queryForAllRawContactIds(ContentResolver cr, long contactId) {
+ Cursor rawContactIdCursor = null;
+ ArrayList<Long> rawContactIds = new ArrayList<Long>();
+ try {
+ rawContactIdCursor = cr.query(RawContacts.CONTENT_URI,
+ new String[] {RawContacts._ID},
+ RawContacts.CONTACT_ID + "=" + contactId, null, null);
+ if (rawContactIdCursor != null) {
+ while (rawContactIdCursor.moveToNext()) {
+ rawContactIds.add(rawContactIdCursor.getLong(0));
+ }
+ }
+ } finally {
+ if (rawContactIdCursor != null) {
+ rawContactIdCursor.close();
+ }
+ }
+ return rawContactIds;
+ }
+
+
+ /**
+ * Utility for creating a standard tab indicator view.
+ *
+ * @param parent The parent ViewGroup to attach the new view to.
+ * @param label The label to display in the tab indicator. If null, not label will be displayed.
+ * @param icon The icon to display. If null, no icon will be displayed.
+ * @return The tab indicator View.
+ */
+ public static View createTabIndicatorView(ViewGroup parent, CharSequence label, Drawable icon) {
+ final LayoutInflater inflater = (LayoutInflater)parent.getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ final View tabIndicator = inflater.inflate(R.layout.tab_indicator, parent, false);
+ tabIndicator.getBackground().setDither(true);
+
+ final TextView tv = (TextView) tabIndicator.findViewById(R.id.tab_title);
+ tv.setText(label);
+
+ final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.tab_icon);
+ iconView.setImageDrawable(icon);
+
+ return tabIndicator;
+ }
+
+ /**
+ * Utility for creating a standard tab indicator view.
+ *
+ * @param context The label to display in the tab indicator. If null, not label will be displayed.
+ * @param parent The parent ViewGroup to attach the new view to.
+ * @param source The {@link ContactsSource} to build the tab view from.
+ * @return The tab indicator View.
+ */
+ public static View createTabIndicatorView(ViewGroup parent, ContactsSource source) {
+ Drawable icon = null;
+ if (source != null) {
+ icon = source.getDisplayIcon(parent.getContext());
+ }
+ return createTabIndicatorView(parent, null, icon);
+ }
+
+ /**
+ * Kick off an intent to initiate a call.
+ */
+ public static void initiateCall(Context context, CharSequence phoneNumber) {
+ Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
+ Uri.fromParts("tel", phoneNumber.toString(), null));
+ context.startActivity(intent);
+ }
+
+ /**
+ * Kick off an intent to initiate an Sms/Mms message.
+ */
+ public static void initiateSms(Context context, CharSequence phoneNumber) {
+ Intent intent = new Intent(Intent.ACTION_SENDTO,
+ Uri.fromParts("sms", phoneNumber.toString(), null));
+ context.startActivity(intent);
+ }
+
+ /**
+ * Test if the given {@link CharSequence} contains any graphic characters,
+ * first checking {@link TextUtils#isEmpty(CharSequence)} to handle null.
+ */
+ public static boolean isGraphic(CharSequence str) {
+ return !TextUtils.isEmpty(str) && TextUtils.isGraphic(str);
+ }
+}
diff --git a/src/com/android/contacts/DialtactsActivity.java b/src/com/android/contacts/DialtactsActivity.java
index 73d702b..208fbf4 100644
--- a/src/com/android/contacts/DialtactsActivity.java
+++ b/src/com/android/contacts/DialtactsActivity.java
@@ -16,29 +16,28 @@
package com.android.contacts;
+import com.android.internal.telephony.ITelephony;
+
import android.app.Activity;
import android.app.TabActivity;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.provider.CallLog;
-import android.provider.Contacts;
import android.provider.CallLog.Calls;
-import android.provider.Contacts.Intents.UI;
+import android.provider.ContactsContract.Intents.UI;
import android.util.Log;
-import android.view.KeyEvent;
import android.view.Window;
import android.widget.TabHost;
-import com.android.internal.telephony.ITelephony;
/**
- * The dialer activity that has one tab with the virtual 12key dialer,
- * and another tab with recent calls in it. This is the container and the tabs
- * are embedded using intents.
+ * The dialer activity that has one tab with the virtual 12key
+ * dialer, a tab with recent calls in it, a tab with the contacts and
+ * a tab with the favorite. This is the container and the tabs are
+ * embedded using intents.
+ * The dialer tab's title is 'phone', a more common name (see strings.xml).
*/
public class DialtactsActivity extends TabActivity implements TabHost.OnTabChangeListener {
private static final String TAG = "Dailtacts";
@@ -49,7 +48,7 @@
private static final int TAB_INDEX_CALL_LOG = 1;
private static final int TAB_INDEX_CONTACTS = 2;
private static final int TAB_INDEX_FAVORITES = 3;
-
+
static final String EXTRA_IGNORE_STATE = "ignore-state";
/** Name of the dialtacts shared preferences */
@@ -59,7 +58,7 @@
static final boolean PREF_FAVORITES_AS_CONTACTS_DEFAULT = false;
private TabHost mTabHost;
- private String mFilterText;
+ private String mFilterText;
private Uri mDialUri;
@Override
@@ -68,7 +67,7 @@
final Intent intent = getIntent();
fixIntent(intent);
-
+
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.dialer_activity);
@@ -83,7 +82,7 @@
setCurrentTab(intent);
- if (intent.getAction().equals(Contacts.Intents.UI.FILTER_CONTACTS_ACTION)
+ if (intent.getAction().equals(UI.FILTER_CONTACTS_ACTION)
&& icicle == null) {
setupFilterText(intent);
}
@@ -92,7 +91,7 @@
@Override
protected void onPause() {
super.onPause();
-
+
int currentTabIndex = mTabHost.getCurrentTab();
if (currentTabIndex == TAB_INDEX_CONTACTS || currentTabIndex == TAB_INDEX_FAVORITES) {
SharedPreferences.Editor editor = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE)
@@ -101,7 +100,7 @@
editor.commit();
}
}
-
+
private void fixIntent(Intent intent) {
// This should be cleaned up: the call key used to send an Intent
// that just said to go to the recent calls list. It now sends this
@@ -112,7 +111,7 @@
setIntent(intent);
}
}
-
+
private void setupCallLogTab() {
// Force the class since overriding tab entries doesn't work
Intent intent = new Intent("com.android.phone.action.RECENT_CALLS");
@@ -156,10 +155,10 @@
/**
* Returns true if the intent is due to hitting the green send key while in a call.
- *
+ *
* @param intent the intent that launched this activity
* @param recentCallsRequest true if the intent is requesting to view recent calls
- * @return true if the intent is due to hitting the green send key while in a call
+ * @return true if the intent is due to hitting the green send key while in a call
*/
private boolean isSendKeyWhileInCall(final Intent intent, final boolean recentCallsRequest) {
// If there is a call in progress go to the call screen
@@ -181,7 +180,7 @@
/**
* Sets the current tab based on the intent's request type
- *
+ *
* @param recentCallsRequest true is the recent calls tab is desired, false otherwise
*/
private void setCurrentTab(Intent intent) {
@@ -191,7 +190,7 @@
finish();
return;
}
-
+
// Dismiss menu provided by any children activities
Activity activity = getLocalActivityManager().
getActivity(mTabHost.getCurrentTabTag());
@@ -235,7 +234,7 @@
fixIntent(newIntent);
setCurrentTab(newIntent);
final String action = newIntent.getAction();
- if (action.equals(Contacts.Intents.UI.FILTER_CONTACTS_ACTION)) {
+ if (action.equals(UI.FILTER_CONTACTS_ACTION)) {
setupFilterText(newIntent);
} else if (isDialIntent(newIntent)) {
setupDialUri(newIntent);
@@ -256,13 +255,13 @@
}
return false;
}
-
+
/**
* Retrieves the filter text stored in {@link #setupFilterText(Intent)}.
* This text originally came from a FILTER_CONTACTS_ACTION intent received
* by this activity. The stored text will then be cleared after after this
* method returns.
- *
+ *
* @return The stored filter text
*/
public String getAndClearFilterText() {
@@ -274,7 +273,7 @@
/**
* Stores the filter text associated with a FILTER_CONTACTS_ACTION intent.
* This is so child activities can check if they are supposed to display a filter.
- *
+ *
* @param intent The intent received in {@link #onNewIntent(Intent)}
*/
private void setupFilterText(Intent intent) {
@@ -282,7 +281,7 @@
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
return;
}
- String filter = intent.getStringExtra(Contacts.Intents.UI.FILTER_TEXT_EXTRA_KEY);
+ String filter = intent.getStringExtra(UI.FILTER_TEXT_EXTRA_KEY);
if (filter != null && filter.length() > 0) {
mFilterText = filter;
}
@@ -292,7 +291,7 @@
* Retrieves the uri stored in {@link #setupDialUri(Intent)}. This uri
* originally came from a dial intent received by this activity. The stored
* uri will then be cleared after after this method returns.
- *
+ *
* @return The stored uri
*/
public Uri getAndClearDialUri() {
@@ -304,7 +303,7 @@
/**
* Stores the uri associated with a dial intent. This is so child activities can
* check if they are supposed to display new dial info.
- *
+ *
* @param intent The intent received in {@link #onNewIntent(Intent)}
*/
private void setupDialUri(Intent intent) {
@@ -316,18 +315,16 @@
}
@Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- // Handle BACK
- if (keyCode == KeyEvent.KEYCODE_BACK && isTaskRoot()) {
+ public void onBackPressed() {
+ if (isTaskRoot()) {
// Instead of stopping, simply push this to the back of the stack.
// This is only done when running at the top of the stack;
// otherwise, we have been launched by someone else so need to
// allow the user to go back to the caller.
moveTaskToBack(false);
- return true;
+ } else {
+ super.onBackPressed();
}
-
- return super.onKeyDown(keyCode, event);
}
/** {@inheritDoc} */
diff --git a/src/com/android/contacts/EditContactActivity.java b/src/com/android/contacts/EditContactActivity.java
deleted file mode 100644
index b89573b..0000000
--- a/src/com/android/contacts/EditContactActivity.java
+++ /dev/null
@@ -1,2202 +0,0 @@
-/*
- * Copyright (C) 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,
- * 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.contacts;
-
-import static com.android.contacts.ContactEntryAdapter.CONTACT_CUSTOM_RINGTONE_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_NAME_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_NOTES_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_PROJECTION;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_SEND_TO_VOICEMAIL_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_PHONETIC_NAME_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_AUX_DATA_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_DATA_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_ID_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_ISPRIMARY_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_KIND_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_LABEL_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_PROJECTION;
-import static com.android.contacts.ContactEntryAdapter.METHODS_TYPE_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_COMPANY_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_ID_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_ISPRIMARY_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_LABEL_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_PROJECTION;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_TITLE_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_TYPE_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.PHONES_ID_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.PHONES_ISPRIMARY_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.PHONES_LABEL_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.PHONES_NUMBER_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.PHONES_PROJECTION;
-import static com.android.contacts.ContactEntryAdapter.PHONES_TYPE_COLUMN;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.ActivityNotFoundException;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.preference.PreferenceManager;
-import android.provider.Contacts;
-import android.provider.Contacts.ContactMethods;
-import android.provider.Contacts.Intents.Insert;
-import android.provider.Contacts.Groups;
-import android.provider.Contacts.Organizations;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
-import android.telephony.PhoneNumberFormattingTextWatcher;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.text.method.TextKeyListener;
-import android.text.method.TextKeyListener.Capitalize;
-import android.util.Log;
-import android.util.SparseBooleanArray;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.inputmethod.EditorInfo;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-
-/**
- * Activity for editing or inserting a contact. Note that if the contact data changes in the
- * background while this activity is running, the updates will be overwritten.
- */
-public final class EditContactActivity extends Activity implements View.OnClickListener,
- TextWatcher, View.OnFocusChangeListener {
- private static final String TAG = "EditContactActivity";
-
- private static final int STATE_UNKNOWN = 0;
- /** Editing an existing contact */
- private static final int STATE_EDIT = 1;
- /** The full insert mode */
- private static final int STATE_INSERT = 2;
-
- /** The launch code when picking a photo and the raw data is returned */
- private static final int PHOTO_PICKED_WITH_DATA = 3021;
-
- /** The launch code when picking a ringtone */
- private static final int RINGTONE_PICKED = 3023;
-
- // These correspond to the string array in resources for picker "other" items
- final static int OTHER_ORGANIZATION = 0;
- final static int OTHER_NOTE = 1;
-
- // Dialog IDs
- final static int DELETE_CONFIRMATION_DIALOG = 2;
-
- // Section IDs
- final static int SECTION_PHONES = 3;
- final static int SECTION_EMAIL = 4;
- final static int SECTION_IM = 5;
- final static int SECTION_POSTAL = 6;
- final static int SECTION_ORG = 7;
- final static int SECTION_NOTE = 8;
-
- // Menu item IDs
- public static final int MENU_ITEM_SAVE = 1;
- public static final int MENU_ITEM_DONT_SAVE = 2;
- public static final int MENU_ITEM_DELETE = 3;
- public static final int MENU_ITEM_PHOTO = 6;
-
- /** Used to represent an invalid type for a contact entry */
- private static final int INVALID_TYPE = -1;
-
- /** The default type for a phone that is added via an intent */
- private static final int DEFAULT_PHONE_TYPE = Phones.TYPE_MOBILE;
-
- /** The default type for an email that is added via an intent */
- private static final int DEFAULT_EMAIL_TYPE = ContactMethods.TYPE_HOME;
-
- /** The default type for a postal address that is added via an intent */
- private static final int DEFAULT_POSTAL_TYPE = ContactMethods.TYPE_HOME;
-
- private int mState; // saved across instances
- private boolean mInsert; // saved across instances
- private Uri mUri; // saved across instances
- /** In insert mode this is the photo */
- private Bitmap mPhoto; // saved across instances
- private boolean mPhotoChanged = false; // saved across instances
-
- private EditText mNameView;
- private ImageView mPhotoImageView;
- private ViewGroup mContentView;
- private LinearLayout mLayout;
- private LayoutInflater mInflater;
- private MenuItem mPhotoMenuItem;
- private boolean mPhotoPresent = false;
- private EditText mPhoneticNameView; // invisible in some locales, but always present
-
- /** Flag marking this contact as changed, meaning we should write changes back. */
- private boolean mContactChanged = false;
-
- // These are accessed by inner classes. They're package scoped to make access more efficient.
- /* package */ ContentResolver mResolver;
- /* package */ ArrayList<EditEntry> mPhoneEntries = new ArrayList<EditEntry>();
- /* package */ ArrayList<EditEntry> mEmailEntries = new ArrayList<EditEntry>();
- /* package */ ArrayList<EditEntry> mImEntries = new ArrayList<EditEntry>();
- /* package */ ArrayList<EditEntry> mPostalEntries = new ArrayList<EditEntry>();
- /* package */ ArrayList<EditEntry> mOrgEntries = new ArrayList<EditEntry>();
- /* package */ ArrayList<EditEntry> mNoteEntries = new ArrayList<EditEntry>();
- /* package */ ArrayList<EditEntry> mOtherEntries = new ArrayList<EditEntry>();
- /* package */ ArrayList<ArrayList<EditEntry>> mSections = new ArrayList<ArrayList<EditEntry>>();
-
- /* package */ static final int MSG_DELETE = 1;
- /* package */ static final int MSG_CHANGE_LABEL = 2;
- /* package */ static final int MSG_ADD_PHONE = 3;
- /* package */ static final int MSG_ADD_EMAIL = 4;
- /* package */ static final int MSG_ADD_POSTAL = 5;
-
- private static final int[] TYPE_PRECEDENCE_PHONES = new int[] {
- Phones.TYPE_MOBILE, Phones.TYPE_HOME, Phones.TYPE_WORK, Phones.TYPE_OTHER
- };
- private static final int[] TYPE_PRECEDENCE_METHODS = new int[] {
- ContactMethods.TYPE_HOME, ContactMethods.TYPE_WORK, ContactMethods.TYPE_OTHER
- };
- private static final int[] TYPE_PRECEDENCE_IM = new int[] {
- ContactMethods.PROTOCOL_GOOGLE_TALK, ContactMethods.PROTOCOL_AIM,
- ContactMethods.PROTOCOL_MSN, ContactMethods.PROTOCOL_YAHOO,
- ContactMethods.PROTOCOL_JABBER
- };
- private static final int[] TYPE_PRECEDENCE_ORG = new int[] {
- Organizations.TYPE_WORK, Organizations.TYPE_OTHER
- };
-
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.photoImage: {
- doPickPhotoAction();
- break;
- }
-
- case R.id.checkable: {
- CheckBox checkBox = (CheckBox) v.findViewById(R.id.checkbox);
- checkBox.toggle();
-
- EditEntry entry = findEntryForView(v);
- entry.data = checkBox.isChecked() ? "1" : "0";
-
- mContactChanged = true;
- break;
- }
-
- case R.id.entry_ringtone: {
- EditEntry entry = findEntryForView(v);
- doPickRingtone(entry);
- break;
- }
-
- case R.id.separator: {
- // Someone clicked on a section header, so handle add action
- int sectionType = (Integer) v.getTag();
- doAddAction(sectionType);
- break;
- }
-
- case R.id.saveButton:
- doSaveAction();
- break;
-
- case R.id.discardButton:
- doRevertAction();
- break;
-
- case R.id.delete: {
- EditEntry entry = findEntryForView(v);
- if (entry != null) {
- // Clear the text and hide the view so it gets saved properly
- ((TextView) entry.view.findViewById(R.id.data)).setText(null);
- entry.view.setVisibility(View.GONE);
- entry.isDeleted = true;
- }
-
- // Force rebuild of views because section headers might need to change
- buildViews();
- break;
- }
-
- case R.id.label: {
- EditEntry entry = findEntryForView(v);
- if (entry != null) {
- String[] labels = getLabelsForKind(this, entry.kind);
- LabelPickedListener listener = new LabelPickedListener(entry, labels);
- new AlertDialog.Builder(EditContactActivity.this)
- .setItems(labels, listener)
- .setTitle(R.string.selectLabel)
- .show();
- }
- break;
- }
- }
- }
-
- private void setPhotoPresent(boolean present) {
- mPhotoPresent = present;
-
- // Correctly scale the contact photo if present, otherwise just center
- // the photo placeholder icon.
- if (mPhotoPresent) {
- mPhotoImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
- } else {
- mPhotoImageView.setImageResource(R.drawable.ic_menu_add_picture);
- mPhotoImageView.setScaleType(ImageView.ScaleType.CENTER);
- }
-
- if (mPhotoMenuItem != null) {
- if (present) {
- mPhotoMenuItem.setTitle(R.string.removePicture);
- mPhotoMenuItem.setIcon(android.R.drawable.ic_menu_delete);
- } else {
- mPhotoMenuItem.setTitle(R.string.addPicture);
- mPhotoMenuItem.setIcon(R.drawable.ic_menu_add_picture);
- }
- }
- }
-
- private EditEntry findEntryForView(View v) {
- // Try to find the entry for this view
- EditEntry entry = null;
- do {
- Object tag = v.getTag();
- if (tag != null && tag instanceof EditEntry) {
- entry = (EditEntry) tag;
- break;
- } else {
- ViewParent parent = v.getParent();
- if (parent != null && parent instanceof View) {
- v = (View) parent;
- } else {
- v = null;
- }
- }
- } while (v != null);
- return entry;
- }
-
- private DialogInterface.OnClickListener mDeleteContactDialogListener =
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int button) {
- mResolver.delete(mUri, null, null);
- finish();
- }
- };
-
- private boolean mMobilePhoneAdded = false;
- private boolean mPrimaryEmailAdded = false;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- mResolver = getContentResolver();
-
- // Build the list of sections
- setupSections();
-
- // Load the UI
- mInflater = getLayoutInflater();
- mContentView = (ViewGroup)mInflater.inflate(R.layout.edit_contact, null);
- setContentView(mContentView);
-
- mLayout = (LinearLayout) findViewById(R.id.list);
- mNameView = (EditText) findViewById(R.id.name);
- mPhotoImageView = (ImageView) findViewById(R.id.photoImage);
- mPhotoImageView.setOnClickListener(this);
- mPhoneticNameView = (EditText) findViewById(R.id.phonetic_name);
-
- // Setup the bottom buttons
- View view = findViewById(R.id.saveButton);
- view.setOnClickListener(this);
- view = findViewById(R.id.discardButton);
- view.setOnClickListener(this);
-
- // Resolve the intent
- mState = STATE_UNKNOWN;
- Intent intent = getIntent();
- String action = intent.getAction();
- mUri = intent.getData();
- if (mUri != null) {
- if (action.equals(Intent.ACTION_EDIT)) {
- if (icicle == null) {
- // Build the entries & views
- buildEntriesForEdit(getIntent().getExtras());
- buildViews();
- }
- setTitle(R.string.editContact_title_edit);
- mState = STATE_EDIT;
- } else if (action.equals(Intent.ACTION_INSERT)) {
- if (icicle == null) {
- // Build the entries & views
- buildEntriesForInsert(getIntent().getExtras());
- buildViews();
- }
- setTitle(R.string.editContact_title_insert);
- mState = STATE_INSERT;
- mInsert = true;
- }
- }
-
- if (mState == STATE_UNKNOWN) {
- Log.e(TAG, "Cannot resolve intent: " + intent);
- finish();
- return;
- }
-
- if (mState == STATE_EDIT) {
- setTitle(getResources().getText(R.string.editContact_title_edit));
- } else {
- setTitle(getResources().getText(R.string.editContact_title_insert));
- }
- }
-
- private void setupSections() {
- mSections.add(mPhoneEntries);
- mSections.add(mEmailEntries);
- mSections.add(mImEntries);
- mSections.add(mPostalEntries);
- mSections.add(mOrgEntries);
- mSections.add(mNoteEntries);
- mSections.add(mOtherEntries);
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
-
- // To store current focus between config changes, follow focus down the
- // view tree, keeping track of any parents with EditEntry tags
- View focusedChild = mContentView.getFocusedChild();
- EditEntry focusedEntry = null;
- while (focusedChild != null) {
- Object tag = focusedChild.getTag();
- if (tag instanceof EditEntry) {
- focusedEntry = (EditEntry) tag;
- }
-
- // Keep going deeper until child isn't a group
- if (focusedChild instanceof ViewGroup) {
- View deeperFocus = ((ViewGroup) focusedChild).getFocusedChild();
- if (deeperFocus != null) {
- focusedChild = deeperFocus;
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- if (focusedChild != null) {
- int requestFocusId = focusedChild.getId();
- int requestCursor = 0;
- if (focusedChild instanceof EditText) {
- requestCursor = ((EditText) focusedChild).getSelectionStart();
- }
-
- // Store focus values in EditEntry if found, otherwise store as
- // generic values
- if (focusedEntry != null) {
- focusedEntry.requestFocusId = requestFocusId;
- focusedEntry.requestCursor = requestCursor;
- } else {
- outState.putInt("requestFocusId", requestFocusId);
- outState.putInt("requestCursor", requestCursor);
- }
- }
-
- outState.putParcelableArrayList("phoneEntries", mPhoneEntries);
- outState.putParcelableArrayList("emailEntries", mEmailEntries);
- outState.putParcelableArrayList("imEntries", mImEntries);
- outState.putParcelableArrayList("postalEntries", mPostalEntries);
- outState.putParcelableArrayList("orgEntries", mOrgEntries);
- outState.putParcelableArrayList("noteEntries", mNoteEntries);
- outState.putParcelableArrayList("otherEntries", mOtherEntries);
- outState.putInt("state", mState);
- outState.putBoolean("insert", mInsert);
- outState.putParcelable("uri", mUri);
- outState.putString("name", mNameView.getText().toString());
- outState.putParcelable("photo", mPhoto);
- outState.putBoolean("photoChanged", mPhotoChanged);
- outState.putString("phoneticName", mPhoneticNameView.getText().toString());
- outState.putBoolean("contactChanged", mContactChanged);
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle inState) {
- mPhoneEntries = inState.getParcelableArrayList("phoneEntries");
- mEmailEntries = inState.getParcelableArrayList("emailEntries");
- mImEntries = inState.getParcelableArrayList("imEntries");
- mPostalEntries = inState.getParcelableArrayList("postalEntries");
- mOrgEntries = inState.getParcelableArrayList("orgEntries");
- mNoteEntries = inState.getParcelableArrayList("noteEntries");
- mOtherEntries = inState.getParcelableArrayList("otherEntries");
- setupSections();
-
- mState = inState.getInt("state");
- mInsert = inState.getBoolean("insert");
- mUri = inState.getParcelable("uri");
- mNameView.setText(inState.getString("name"));
- mPhoto = inState.getParcelable("photo");
- if (mPhoto != null) {
- mPhotoImageView.setImageBitmap(mPhoto);
- setPhotoPresent(true);
- } else {
- mPhotoImageView.setImageResource(R.drawable.ic_contact_picture);
- setPhotoPresent(false);
- }
- mPhotoChanged = inState.getBoolean("photoChanged");
- mPhoneticNameView.setText(inState.getString("phoneticName"));
- mContactChanged = inState.getBoolean("contactChanged");
-
- // Now that everything is restored, build the view
- buildViews();
-
- // Try restoring any generally requested focus
- int requestFocusId = inState.getInt("requestFocusId", View.NO_ID);
- View focusedChild = mContentView.findViewById(requestFocusId);
- if (focusedChild != null) {
- focusedChild.requestFocus();
- if (focusedChild instanceof EditText) {
- int requestCursor = inState.getInt("requestCursor", 0);
- ((EditText) focusedChild).setSelection(requestCursor);
- }
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode != RESULT_OK) {
- return;
- }
-
- switch (requestCode) {
- case PHOTO_PICKED_WITH_DATA: {
- final Bundle extras = data.getExtras();
- if (extras != null) {
- Bitmap photo = extras.getParcelable("data");
- mPhoto = photo;
- mPhotoChanged = true;
- mPhotoImageView.setImageBitmap(photo);
- setPhotoPresent(true);
- }
- break;
- }
-
- case RINGTONE_PICKED: {
- Uri pickedUri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
- handleRingtonePicked(pickedUri);
- mContactChanged = true;
- break;
- }
- }
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_BACK: {
- doSaveAction();
- return true;
- }
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- menu.add(0, MENU_ITEM_SAVE, 0, R.string.menu_done)
- .setIcon(android.R.drawable.ic_menu_save)
- .setAlphabeticShortcut('\n');
- menu.add(0, MENU_ITEM_DONT_SAVE, 0, R.string.menu_doNotSave)
- .setIcon(android.R.drawable.ic_menu_close_clear_cancel)
- .setAlphabeticShortcut('q');
- if (!mInsert) {
- menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_deleteContact)
- .setIcon(android.R.drawable.ic_menu_delete);
- }
-
- mPhotoMenuItem = menu.add(0, MENU_ITEM_PHOTO, 0, null);
- // Updates the state of the menu item
- setPhotoPresent(mPhotoPresent);
-
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case MENU_ITEM_SAVE:
- doSaveAction();
- return true;
-
- case MENU_ITEM_DONT_SAVE:
- doRevertAction();
- return true;
-
- case MENU_ITEM_DELETE:
- // Get confirmation
- showDialog(DELETE_CONFIRMATION_DIALOG);
- return true;
-
- case MENU_ITEM_PHOTO:
- if (!mPhotoPresent) {
- doPickPhotoAction();
- } else {
- doRemovePhotoAction();
- }
- return true;
- }
-
- return false;
- }
-
- /**
- * Try guessing the next-best type of {@link EditEntry} to insert into the
- * given list. We walk down the precedence list until we find a type that
- * doesn't exist yet, or default to the lowest ranking type.
- */
- private int guessNextType(ArrayList<EditEntry> entries, int[] precedenceList) {
- // Keep track of the types we've seen already
- SparseBooleanArray existAlready = new SparseBooleanArray(entries.size());
- for (int i = entries.size() - 1; i >= 0; i--) {
- EditEntry entry = entries.get(i);
- if (!entry.isDeleted) {
- existAlready.put(entry.type, true);
- }
- }
-
- // Pick the first item we haven't seen
- for (int type : precedenceList) {
- if (!existAlready.get(type, false)) {
- return type;
- }
- }
-
- // Otherwise default to last item
- return precedenceList[precedenceList.length - 1];
- }
-
- private void doAddAction(int sectionType) {
- EditEntry entry = null;
- switch (sectionType) {
- case SECTION_PHONES: {
- // Try figuring out which type to insert next
- int nextType = guessNextType(mPhoneEntries, TYPE_PRECEDENCE_PHONES);
- entry = EditEntry.newPhoneEntry(EditContactActivity.this,
- Uri.withAppendedPath(mUri, People.Phones.CONTENT_DIRECTORY),
- nextType);
- mPhoneEntries.add(entry);
- break;
- }
- case SECTION_EMAIL: {
- // Try figuring out which type to insert next
- int nextType = guessNextType(mEmailEntries, TYPE_PRECEDENCE_METHODS);
- entry = EditEntry.newEmailEntry(EditContactActivity.this,
- Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY),
- nextType);
- mEmailEntries.add(entry);
- break;
- }
- case SECTION_IM: {
- // Try figuring out which type to insert next
- int nextType = guessNextType(mImEntries, TYPE_PRECEDENCE_IM);
- entry = EditEntry.newImEntry(EditContactActivity.this,
- Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY),
- nextType);
- mImEntries.add(entry);
- break;
- }
- case SECTION_POSTAL: {
- int nextType = guessNextType(mPostalEntries, TYPE_PRECEDENCE_METHODS);
- entry = EditEntry.newPostalEntry(EditContactActivity.this,
- Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY),
- nextType);
- mPostalEntries.add(entry);
- break;
- }
- case SECTION_ORG: {
- int nextType = guessNextType(mOrgEntries, TYPE_PRECEDENCE_ORG);
- entry = EditEntry.newOrganizationEntry(EditContactActivity.this,
- Uri.withAppendedPath(mUri, Organizations.CONTENT_DIRECTORY),
- nextType);
- mOrgEntries.add(entry);
- break;
- }
- case SECTION_NOTE: {
- entry = EditEntry.newNotesEntry(EditContactActivity.this, null, mUri);
- mNoteEntries.add(entry);
- break;
- }
- }
-
- // Rebuild the views if needed
- if (entry != null) {
- buildViews();
- mContactChanged = true;
-
- View dataView = entry.view.findViewById(R.id.data);
- if (dataView == null) {
- entry.view.requestFocus();
- } else {
- dataView.requestFocus();
- }
- }
- }
-
- private void doRevertAction() {
- finish();
- }
-
- private void doPickPhotoAction() {
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
- // TODO: get these values from constants somewhere
- intent.setType("image/*");
- intent.putExtra("crop", "true");
- intent.putExtra("aspectX", 1);
- intent.putExtra("aspectY", 1);
- intent.putExtra("outputX", 96);
- intent.putExtra("outputY", 96);
- try {
- intent.putExtra("return-data", true);
- startActivityForResult(intent, PHOTO_PICKED_WITH_DATA);
- } catch (ActivityNotFoundException e) {
- new AlertDialog.Builder(EditContactActivity.this)
- .setTitle(R.string.errorDialogTitle)
- .setMessage(R.string.photoPickerNotFoundText)
- .setPositiveButton(android.R.string.ok, null)
- .show();
- }
- }
-
- private void doRemovePhotoAction() {
- mPhoto = null;
- mPhotoChanged = true;
- setPhotoPresent(false);
- }
-
- private void doPickRingtone(EditEntry entry) {
- Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
- // Allow user to pick 'Default'
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
- // Show only ringtones
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE);
- // Don't show 'Silent'
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false);
-
- Uri ringtoneUri;
- if (entry.data != null) {
- ringtoneUri = Uri.parse(entry.data);
- } else {
- // Otherwise pick default ringtone Uri so that something is selected.
- ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
- }
-
- // Put checkmark next to the current ringtone for this contact
- intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, ringtoneUri);
- // Launch!
- startActivityForResult(intent, RINGTONE_PICKED);
- }
-
- private void handleRingtonePicked(Uri pickedUri) {
- EditEntry entry = getOtherEntry(People.CUSTOM_RINGTONE);
- if (entry == null) {
- Log.w(TAG, "Ringtone picked but could not find ringtone entry");
- return;
- }
-
- if (pickedUri == null || RingtoneManager.isDefault(pickedUri)) {
- entry.data = null;
- } else {
- entry.data = pickedUri.toString();
- }
-
- updateRingtoneView(entry);
- }
-
- private void updateRingtoneView(EditEntry entry) {
- String ringtoneName;
- if (entry.data == null) {
- ringtoneName = getString(R.string.default_ringtone);
- } else {
- Uri ringtoneUri = Uri.parse(entry.data);
- Ringtone ringtone = RingtoneManager.getRingtone(this, ringtoneUri);
- if (ringtone == null) {
- Log.w(TAG, "ringtone's URI doesn't resolve to a Ringtone");
- return;
- }
- ringtoneName = ringtone.getTitle(this);
- }
-
- updateDataView(entry, ringtoneName);
- }
-
- private void updateDataView(EditEntry entry, String text) {
- TextView dataView = (TextView) entry.view.findViewById(R.id.data);
- dataView.setText(text);
- }
-
- @Override
- protected Dialog onCreateDialog(int id) {
- switch (id) {
- case DELETE_CONFIRMATION_DIALOG:
- return new AlertDialog.Builder(EditContactActivity.this)
- .setTitle(R.string.deleteConfirmation_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(R.string.deleteConfirmation)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(android.R.string.ok, mDeleteContactDialogListener)
- .setCancelable(false)
- .create();
- }
- return super.onCreateDialog(id);
- }
-
- static String[] getLabelsForKind(Context context, int kind) {
- final Resources resources = context.getResources();
- switch (kind) {
- case Contacts.KIND_PHONE:
- return resources.getStringArray(android.R.array.phoneTypes);
- case Contacts.KIND_EMAIL:
- return resources.getStringArray(android.R.array.emailAddressTypes);
- case Contacts.KIND_POSTAL:
- return resources.getStringArray(android.R.array.postalAddressTypes);
- case Contacts.KIND_IM:
- return resources.getStringArray(android.R.array.imProtocols);
- case Contacts.KIND_ORGANIZATION:
- return resources.getStringArray(android.R.array.organizationTypes);
- case EditEntry.KIND_CONTACT:
- return resources.getStringArray(R.array.otherLabels);
- }
- return null;
- }
-
- int getTypeFromLabelPosition(CharSequence[] labels, int labelPosition) {
- // In the UI Custom... comes last, but it is uses the constant 0
- // so it is in the same location across the various kinds. Fix up the
- // position to a valid type here.
- if (labelPosition == labels.length - 1) {
- return ContactMethods.TYPE_CUSTOM;
- } else {
- return labelPosition + 1;
- }
- }
-
- private EditEntry getOtherEntry(String column) {
- for (int i = mOtherEntries.size() - 1; i >= 0; i--) {
- EditEntry entry = mOtherEntries.get(i);
- if (isOtherEntry(entry, column)) {
- return entry;
- }
- }
- return null;
- }
-
- private static boolean isOtherEntry(EditEntry entry, String column) {
- return entry != null && entry.column != null && entry.column.equals(column);
- }
-
- private void createCustomPicker(final EditEntry entry, final ArrayList<EditEntry> addTo) {
- final EditText label = new EditText(this);
- label.setKeyListener(TextKeyListener.getInstance(false, Capitalize.WORDS));
- label.requestFocus();
- new AlertDialog.Builder(this)
- .setView(label)
- .setTitle(R.string.customLabelPickerTitle)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- entry.setLabel(EditContactActivity.this, ContactMethods.TYPE_CUSTOM,
- label.getText().toString());
- mContactChanged = true;
-
- if (addTo != null) {
- addTo.add(entry);
- buildViews();
- entry.view.requestFocus(View.FOCUS_DOWN);
- }
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .show();
- }
-
- /**
- * Saves or creates the contact based on the mode, and if sucessful finishes the activity.
- */
- private void doSaveAction() {
- // Save or create the contact if needed
- switch (mState) {
- case STATE_EDIT:
- save();
- break;
-
- case STATE_INSERT:
- create();
- break;
-
- default:
- Log.e(TAG, "Unknown state in doSaveOrCreate: " + mState);
- break;
- }
- finish();
- }
-
- /**
- * Save the various fields to the existing contact.
- */
- private void save() {
- ContentValues values = new ContentValues();
- String data;
- int numValues = 0;
-
- // Handle the name and send to voicemail specially
- final String name = mNameView.getText().toString();
- if (name != null && TextUtils.isGraphic(name)) {
- numValues++;
- }
- values.put(People.NAME, name);
- values.put(People.PHONETIC_NAME, mPhoneticNameView.getText().toString());
- mResolver.update(mUri, values, null, null);
-
- if (mPhotoChanged) {
- // Only write the photo if it's changed, since we don't initially load mPhoto
- if (mPhoto != null) {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- mPhoto.compress(Bitmap.CompressFormat.JPEG, 75, stream);
- Contacts.People.setPhotoData(mResolver, mUri, stream.toByteArray());
- } else {
- Contacts.People.setPhotoData(mResolver, mUri, null);
- }
- }
-
- int entryCount = ContactEntryAdapter.countEntries(mSections, false);
- for (int i = 0; i < entryCount; i++) {
- EditEntry entry = ContactEntryAdapter.getEntry(mSections, i, false);
- int kind = entry.kind;
- data = entry.getData();
- boolean empty = data == null || !TextUtils.isGraphic(data);
- if (kind == EditEntry.KIND_CONTACT) {
- values.clear();
- if (!empty) {
- values.put(entry.column, data);
- mResolver.update(entry.uri, values, null, null);
- if (!People.CUSTOM_RINGTONE.equals(entry.column) &&
- !People.SEND_TO_VOICEMAIL.equals(entry.column)) {
- numValues++;
- }
- } else {
- values.put(entry.column, (String) null);
- mResolver.update(entry.uri, values, null, null);
- }
- } else {
- if (!empty) {
- values.clear();
- entry.toValues(values);
- if (entry.id != 0) {
- mResolver.update(entry.uri, values, null, null);
- } else {
- mResolver.insert(entry.uri, values);
- }
- if (!People.CUSTOM_RINGTONE.equals(entry.column) &&
- !People.SEND_TO_VOICEMAIL.equals(entry.column)) {
- numValues++;
- }
- } else if (entry.id != 0) {
- mResolver.delete(entry.uri, null, null);
- }
- }
- }
-
- if (numValues == 0) {
- // The contact is completely empty, delete it
- mResolver.delete(mUri, null, null);
- mUri = null;
- setResult(RESULT_CANCELED);
- } else {
- // Add the entry to the my contacts group if it isn't there already
- People.addToMyContactsGroup(mResolver, ContentUris.parseId(mUri));
- setResult(RESULT_OK, new Intent().setData(mUri));
-
- // Only notify user if we actually changed contact
- if (mContactChanged || mPhotoChanged) {
- Toast.makeText(this, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
- }
- }
- }
-
- /**
- * Takes the entered data and saves it to a new contact.
- */
- private void create() {
- ContentValues values = new ContentValues();
- String data;
- int numValues = 0;
-
- // Create the contact itself
- final String name = mNameView.getText().toString();
- if (name != null && TextUtils.isGraphic(name)) {
- numValues++;
- }
- values.put(People.NAME, name);
- values.put(People.PHONETIC_NAME, mPhoneticNameView.getText().toString());
-
- // Add the contact to the My Contacts group
- Uri contactUri = People.createPersonInMyContactsGroup(mResolver, values);
-
- // Add the contact to the group that is being displayed in the contact list
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- int displayType = prefs.getInt(ContactsListActivity.PREF_DISPLAY_TYPE,
- ContactsListActivity.DISPLAY_TYPE_UNKNOWN);
- if (displayType == ContactsListActivity.DISPLAY_TYPE_USER_GROUP) {
- String displayGroup = prefs.getString(ContactsListActivity.PREF_DISPLAY_INFO,
- null);
- if (!TextUtils.isEmpty(displayGroup)) {
- People.addToGroup(mResolver, ContentUris.parseId(contactUri), displayGroup);
- }
- } else {
- // Check to see if we're not syncing everything and if so if My Contacts is synced.
- // If it isn't then the created contact can end up not in any groups that are
- // currently synced and end up getting removed from the phone, which is really bad.
- boolean syncingEverything = !"0".equals(Contacts.Settings.getSetting(mResolver, null,
- Contacts.Settings.SYNC_EVERYTHING));
- if (!syncingEverything) {
- boolean syncingMyContacts = false;
- Cursor c = mResolver.query(Groups.CONTENT_URI, new String[] { Groups.SHOULD_SYNC },
- Groups.SYSTEM_ID + "=?", new String[] { Groups.GROUP_MY_CONTACTS }, null);
- if (c != null) {
- try {
- if (c.moveToFirst()) {
- syncingMyContacts = !"0".equals(c.getString(0));
- }
- } finally {
- c.close();
- }
- }
-
- if (!syncingMyContacts) {
- // Not syncing My Contacts, so find a group that is being synced and stick
- // the contact in there. We sort the list so at least all contacts
- // will appear in the same group.
- c = mResolver.query(Groups.CONTENT_URI, new String[] { Groups._ID },
- Groups.SHOULD_SYNC + "!=0", null, Groups.DEFAULT_SORT_ORDER);
- if (c != null) {
- try {
- if (c.moveToFirst()) {
- People.addToGroup(mResolver, ContentUris.parseId(contactUri),
- c.getLong(0));
- }
- } finally {
- c.close();
- }
- }
- }
- }
- }
-
- // Handle the photo
- if (mPhoto != null) {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- mPhoto.compress(Bitmap.CompressFormat.JPEG, 75, stream);
- Contacts.People.setPhotoData(getContentResolver(), contactUri, stream.toByteArray());
- }
-
- // Create the contact methods
- int entryCount = ContactEntryAdapter.countEntries(mSections, false);
- for (int i = 0; i < entryCount; i++) {
- EditEntry entry = ContactEntryAdapter.getEntry(mSections, i, false);
- if (entry.kind != EditEntry.KIND_CONTACT) {
- values.clear();
- if (entry.toValues(values)) {
- // Only create the entry if there is data
- entry.uri = mResolver.insert(
- Uri.withAppendedPath(contactUri, entry.contentDirectory), values);
- entry.id = ContentUris.parseId(entry.uri);
- if (!People.CUSTOM_RINGTONE.equals(entry.column) &&
- !People.SEND_TO_VOICEMAIL.equals(entry.column)) {
- numValues++;
- }
- }
- } else {
- // Update the contact with any straggling data, like notes
- data = entry.getData();
- values.clear();
- if (data != null && TextUtils.isGraphic(data)) {
- values.put(entry.column, data);
- mResolver.update(contactUri, values, null, null);
- if (!People.CUSTOM_RINGTONE.equals(entry.column) &&
- !People.SEND_TO_VOICEMAIL.equals(entry.column)) {
- numValues++;
- }
- }
- }
- }
-
- if (numValues == 0) {
- mResolver.delete(contactUri, null, null);
- setResult(RESULT_CANCELED);
- } else {
- mUri = contactUri;
- Intent resultIntent = new Intent()
- .setData(mUri)
- .putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
- setResult(RESULT_OK, resultIntent);
- Toast.makeText(this, R.string.contactCreatedToast, Toast.LENGTH_SHORT).show();
- }
- }
-
- /**
- * Build up the entries to display on the screen.
- *
- * @param extras the extras used to start this activity, may be null
- */
- private void buildEntriesForEdit(Bundle extras) {
- Cursor personCursor = mResolver.query(mUri, CONTACT_PROJECTION, null, null, null);
- if (personCursor == null) {
- Log.e(TAG, "invalid contact uri: " + mUri);
- finish();
- return;
- } else if (!personCursor.moveToFirst()) {
- Log.e(TAG, "invalid contact uri: " + mUri);
- finish();
- personCursor.close();
- return;
- }
-
- // Clear out the old entries
- int numSections = mSections.size();
- for (int i = 0; i < numSections; i++) {
- mSections.get(i).clear();
- }
-
- EditEntry entry;
-
- // Name
- mNameView.setText(personCursor.getString(CONTACT_NAME_COLUMN));
- mNameView.addTextChangedListener(this);
-
- // Photo
- mPhoto = People.loadContactPhoto(this, mUri, 0, null);
- if (mPhoto == null) {
- setPhotoPresent(false);
- } else {
- setPhotoPresent(true);
- mPhotoImageView.setImageBitmap(mPhoto);
- }
-
- // Organizations
- Uri organizationsUri = Uri.withAppendedPath(mUri, Organizations.CONTENT_DIRECTORY);
- Cursor organizationsCursor = mResolver.query(organizationsUri, ORGANIZATIONS_PROJECTION,
- null, null, null);
-
- if (organizationsCursor != null) {
- while (organizationsCursor.moveToNext()) {
- int type = organizationsCursor.getInt(ORGANIZATIONS_TYPE_COLUMN);
- String label = organizationsCursor.getString(ORGANIZATIONS_LABEL_COLUMN);
- String company = organizationsCursor.getString(ORGANIZATIONS_COMPANY_COLUMN);
- String title = organizationsCursor.getString(ORGANIZATIONS_TITLE_COLUMN);
- long id = organizationsCursor.getLong(ORGANIZATIONS_ID_COLUMN);
- Uri uri = ContentUris.withAppendedId(Organizations.CONTENT_URI, id);
-
- // Add an organization entry
- entry = EditEntry.newOrganizationEntry(this, label, type, company, title, uri, id);
- entry.isPrimary = organizationsCursor.getLong(ORGANIZATIONS_ISPRIMARY_COLUMN) != 0;
- mOrgEntries.add(entry);
- }
- organizationsCursor.close();
- }
-
- // Notes
- if (!personCursor.isNull(CONTACT_NOTES_COLUMN)) {
- entry = EditEntry.newNotesEntry(this, personCursor.getString(CONTACT_NOTES_COLUMN),
- mUri);
- mNoteEntries.add(entry);
- }
-
- // Ringtone
- entry = EditEntry.newRingtoneEntry(this,
- personCursor.getString(CONTACT_CUSTOM_RINGTONE_COLUMN), mUri);
- mOtherEntries.add(entry);
-
- // Send to voicemail
- entry = EditEntry.newSendToVoicemailEntry(this,
- personCursor.getString(CONTACT_SEND_TO_VOICEMAIL_COLUMN), mUri);
- mOtherEntries.add(entry);
-
- // Phonetic name
- mPhoneticNameView.setText(personCursor.getString(CONTACT_PHONETIC_NAME_COLUMN));
- mPhoneticNameView.addTextChangedListener(this);
-
- personCursor.close();
-
- // Build up the phone entries
- Uri phonesUri = Uri.withAppendedPath(mUri, People.Phones.CONTENT_DIRECTORY);
- Cursor phonesCursor = mResolver.query(phonesUri, PHONES_PROJECTION,
- null, null, null);
-
- if (phonesCursor != null) {
- while (phonesCursor.moveToNext()) {
- int type = phonesCursor.getInt(PHONES_TYPE_COLUMN);
- String label = phonesCursor.getString(PHONES_LABEL_COLUMN);
- String number = phonesCursor.getString(PHONES_NUMBER_COLUMN);
- long id = phonesCursor.getLong(PHONES_ID_COLUMN);
- boolean isPrimary = phonesCursor.getLong(PHONES_ISPRIMARY_COLUMN) != 0;
- Uri uri = ContentUris.withAppendedId(phonesUri, id);
-
- // Add a phone number entry
- entry = EditEntry.newPhoneEntry(this, label, type, number, uri, id);
- entry.isPrimary = isPrimary;
- mPhoneEntries.add(entry);
-
- // Keep track of which primary types have been added
- if (type == Phones.TYPE_MOBILE) {
- mMobilePhoneAdded = true;
- }
- }
-
- phonesCursor.close();
- }
-
- // Build the contact method entries
- Uri methodsUri = Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY);
- Cursor methodsCursor = mResolver.query(methodsUri, METHODS_PROJECTION, null, null, null);
-
- if (methodsCursor != null) {
- while (methodsCursor.moveToNext()) {
- int kind = methodsCursor.getInt(METHODS_KIND_COLUMN);
- String label = methodsCursor.getString(METHODS_LABEL_COLUMN);
- String data = methodsCursor.getString(METHODS_DATA_COLUMN);
- String auxData = methodsCursor.getString(METHODS_AUX_DATA_COLUMN);
- int type = methodsCursor.getInt(METHODS_TYPE_COLUMN);
- long id = methodsCursor.getLong(METHODS_ID_COLUMN);
- boolean isPrimary = methodsCursor.getLong(METHODS_ISPRIMARY_COLUMN) != 0;
- Uri uri = ContentUris.withAppendedId(methodsUri, id);
-
- switch (kind) {
- case Contacts.KIND_EMAIL: {
- entry = EditEntry.newEmailEntry(this, label, type, data, uri, id);
- entry.isPrimary = isPrimary;
- mEmailEntries.add(entry);
-
- if (isPrimary) {
- mPrimaryEmailAdded = true;
- }
- break;
- }
-
- case Contacts.KIND_POSTAL: {
- entry = EditEntry.newPostalEntry(this, label, type, data, uri, id);
- entry.isPrimary = isPrimary;
- mPostalEntries.add(entry);
- break;
- }
-
- case Contacts.KIND_IM: {
- Object protocolObj = ContactMethods.decodeImProtocol(auxData);
- if (protocolObj == null) {
- // Invalid IM protocol, log it then ignore.
- Log.e(TAG, "Couldn't decode IM protocol: " + auxData);
- continue;
- } else {
- if (protocolObj instanceof Number) {
- int protocol = ((Number) protocolObj).intValue();
- entry = EditEntry.newImEntry(this,
- getLabelsForKind(this, Contacts.KIND_IM)[protocol], protocol,
- data, uri, id);
- } else {
- entry = EditEntry.newImEntry(this, protocolObj.toString(), -1, data,
- uri, id);
- }
- mImEntries.add(entry);
- }
- break;
- }
- }
- }
-
- methodsCursor.close();
- }
-
- // Add values from the extras, if there are any
- if (extras != null) {
- addFromExtras(extras, phonesUri, methodsUri);
- }
-
- // Add the base types if needed
- if (!mMobilePhoneAdded) {
- entry = EditEntry.newPhoneEntry(this,
- Uri.withAppendedPath(mUri, People.Phones.CONTENT_DIRECTORY),
- DEFAULT_PHONE_TYPE);
- mPhoneEntries.add(entry);
- }
-
- if (!mPrimaryEmailAdded) {
- entry = EditEntry.newEmailEntry(this,
- Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY),
- DEFAULT_EMAIL_TYPE);
- entry.isPrimary = true;
- mEmailEntries.add(entry);
- }
-
- mContactChanged = false;
- }
-
- /**
- * Build the list of EditEntries for full mode insertions.
- *
- * @param extras the extras used to start this activity, may be null
- */
- private void buildEntriesForInsert(Bundle extras) {
- // Clear out the old entries
- int numSections = mSections.size();
- for (int i = 0; i < numSections; i++) {
- mSections.get(i).clear();
- }
-
- EditEntry entry;
-
- // Check the intent extras
- if (extras != null) {
- addFromExtras(extras, null, null);
- }
-
- // Photo
- mPhotoImageView.setImageResource(R.drawable.ic_contact_picture);
-
- // Add the base entries if they're not already present
- if (!mMobilePhoneAdded) {
- entry = EditEntry.newPhoneEntry(this, null, Phones.TYPE_MOBILE);
- entry.isPrimary = true;
- mPhoneEntries.add(entry);
- }
-
- if (!mPrimaryEmailAdded) {
- entry = EditEntry.newEmailEntry(this, null, DEFAULT_EMAIL_TYPE);
- entry.isPrimary = true;
- mEmailEntries.add(entry);
- }
-
- // Ringtone
- entry = EditEntry.newRingtoneEntry(this, null, mUri);
- mOtherEntries.add(entry);
-
- // Send to voicemail
- entry = EditEntry.newSendToVoicemailEntry(this, "0", mUri);
- mOtherEntries.add(entry);
- }
-
- private void addFromExtras(Bundle extras, Uri phonesUri, Uri methodsUri) {
- EditEntry entry;
-
- // Read the name from the bundle
- CharSequence name = extras.getCharSequence(Insert.NAME);
- if (name != null && TextUtils.isGraphic(name)) {
- mNameView.setText(name);
- }
-
- // Read the phonetic name from the bundle
- CharSequence phoneticName = extras.getCharSequence(Insert.PHONETIC_NAME);
- if (!TextUtils.isEmpty(phoneticName)) {
- mPhoneticNameView.setText(phoneticName);
- }
-
- // Postal entries from extras
- CharSequence postal = extras.getCharSequence(Insert.POSTAL);
- int postalType = extras.getInt(Insert.POSTAL_TYPE, INVALID_TYPE);
- if (!TextUtils.isEmpty(postal) && postalType == INVALID_TYPE) {
- postalType = DEFAULT_POSTAL_TYPE;
- }
-
- if (postalType != INVALID_TYPE) {
- entry = EditEntry.newPostalEntry(this, null, postalType, postal.toString(),
- methodsUri, 0);
- entry.isPrimary = extras.getBoolean(Insert.POSTAL_ISPRIMARY);
- mPostalEntries.add(entry);
- }
-
- // Email entries from extras
- addEmailFromExtras(extras, methodsUri, Insert.EMAIL, Insert.EMAIL_TYPE,
- Insert.EMAIL_ISPRIMARY);
- addEmailFromExtras(extras, methodsUri, Insert.SECONDARY_EMAIL, Insert.SECONDARY_EMAIL_TYPE,
- null);
- addEmailFromExtras(extras, methodsUri, Insert.TERTIARY_EMAIL, Insert.TERTIARY_EMAIL_TYPE,
- null);
-
- // Phone entries from extras
- addPhoneFromExtras(extras, phonesUri, Insert.PHONE, Insert.PHONE_TYPE,
- Insert.PHONE_ISPRIMARY);
- addPhoneFromExtras(extras, phonesUri, Insert.SECONDARY_PHONE, Insert.SECONDARY_PHONE_TYPE,
- null);
- addPhoneFromExtras(extras, phonesUri, Insert.TERTIARY_PHONE, Insert.TERTIARY_PHONE_TYPE,
- null);
-
- // IM entries from extras
- CharSequence imHandle = extras.getCharSequence(Insert.IM_HANDLE);
- CharSequence imProtocol = extras.getCharSequence(Insert.IM_PROTOCOL);
-
- if (imHandle != null && imProtocol != null) {
- Object protocolObj = ContactMethods.decodeImProtocol(imProtocol.toString());
- if (protocolObj instanceof Number) {
- int protocol = ((Number) protocolObj).intValue();
- entry = EditEntry.newImEntry(this,
- getLabelsForKind(this, Contacts.KIND_IM)[protocol], protocol,
- imHandle.toString(), methodsUri, 0);
- } else {
- entry = EditEntry.newImEntry(this, protocolObj.toString(), -1, imHandle.toString(),
- methodsUri, 0);
- }
- entry.isPrimary = extras.getBoolean(Insert.IM_ISPRIMARY);
- mImEntries.add(entry);
- }
- }
-
- private void addEmailFromExtras(Bundle extras, Uri methodsUri, String emailField,
- String typeField, String primaryField) {
- CharSequence email = extras.getCharSequence(emailField);
-
- // Correctly handle String in typeField as TYPE_CUSTOM
- int emailType = INVALID_TYPE;
- String customLabel = null;
- if(extras.get(typeField) instanceof String) {
- emailType = ContactMethods.TYPE_CUSTOM;
- customLabel = extras.getString(typeField);
- } else {
- emailType = extras.getInt(typeField, INVALID_TYPE);
- }
-
- if (!TextUtils.isEmpty(email) && emailType == INVALID_TYPE) {
- emailType = DEFAULT_EMAIL_TYPE;
- mPrimaryEmailAdded = true;
- }
-
- if (emailType != INVALID_TYPE) {
- EditEntry entry = EditEntry.newEmailEntry(this, customLabel, emailType, email.toString(),
- methodsUri, 0);
- entry.isPrimary = (primaryField == null) ? false : extras.getBoolean(primaryField);
- mEmailEntries.add(entry);
-
- // Keep track of which primary types have been added
- if (entry.isPrimary) {
- mPrimaryEmailAdded = true;
- }
- }
- }
-
- private void addPhoneFromExtras(Bundle extras, Uri phonesUri, String phoneField,
- String typeField, String primaryField) {
- CharSequence phoneNumber = extras.getCharSequence(phoneField);
-
- // Correctly handle String in typeField as TYPE_CUSTOM
- int phoneType = INVALID_TYPE;
- String customLabel = null;
- if(extras.get(typeField) instanceof String) {
- phoneType = Phones.TYPE_CUSTOM;
- customLabel = extras.getString(typeField);
- } else {
- phoneType = extras.getInt(typeField, INVALID_TYPE);
- }
-
- if (!TextUtils.isEmpty(phoneNumber) && phoneType == INVALID_TYPE) {
- phoneType = DEFAULT_PHONE_TYPE;
- }
-
- if (phoneType != INVALID_TYPE) {
- EditEntry entry = EditEntry.newPhoneEntry(this, customLabel, phoneType,
- phoneNumber.toString(), phonesUri, 0);
- entry.isPrimary = (primaryField == null) ? false : extras.getBoolean(primaryField);
- mPhoneEntries.add(entry);
-
- // Keep track of which primary types have been added
- if (phoneType == Phones.TYPE_MOBILE) {
- mMobilePhoneAdded = true;
- }
- }
- }
-
- /**
- * Removes all existing views, builds new ones for all the entries, and adds them.
- */
- private void buildViews() {
- // Remove existing views
- final LinearLayout layout = mLayout;
- layout.removeAllViews();
-
- buildViewsForSection(layout, mPhoneEntries,
- R.string.listSeparatorCallNumber_edit, SECTION_PHONES);
- buildViewsForSection(layout, mEmailEntries,
- R.string.listSeparatorSendEmail_edit, SECTION_EMAIL);
- buildViewsForSection(layout, mImEntries,
- R.string.listSeparatorSendIm_edit, SECTION_IM);
- buildViewsForSection(layout, mPostalEntries,
- R.string.listSeparatorMapAddress_edit, SECTION_POSTAL);
- buildViewsForSection(layout, mOrgEntries,
- R.string.listSeparatorOrganizations, SECTION_ORG);
- buildViewsForSection(layout, mNoteEntries,
- R.string.label_notes, SECTION_NOTE);
-
- buildOtherViews(layout, mOtherEntries);
- }
-
-
- /**
- * Builds the views for a specific section.
- *
- * @param layout the container
- * @param section the section to build the views for
- */
- private void buildViewsForSection(final LinearLayout layout, ArrayList<EditEntry> section,
- int separatorResource, int sectionType) {
-
- View divider = mInflater.inflate(R.layout.edit_divider, layout, false);
- layout.addView(divider);
-
- // Count up undeleted children
- int activeChildren = 0;
- for (int i = section.size() - 1; i >= 0; i--) {
- EditEntry entry = section.get(i);
- if (!entry.isDeleted) {
- activeChildren++;
- }
- }
-
- // Build the correct group header based on undeleted children
- ViewGroup header;
- if (activeChildren == 0) {
- header = (ViewGroup) mInflater.inflate(R.layout.edit_separator_alone, layout, false);
- } else {
- header = (ViewGroup) mInflater.inflate(R.layout.edit_separator, layout, false);
- }
-
- // Because we're emulating a ListView, we need to handle focus changes
- // with some additional logic.
- header.setOnFocusChangeListener(this);
-
- TextView text = (TextView) header.findViewById(R.id.text);
- text.setText(getText(separatorResource));
-
- // Force TextView to always default color if we have children. This makes sure
- // we don't change color when parent is pressed.
- if (activeChildren > 0) {
- ColorStateList stateList = text.getTextColors();
- text.setTextColor(stateList.getDefaultColor());
- }
-
- View addView = header.findViewById(R.id.separator);
- addView.setTag(Integer.valueOf(sectionType));
- addView.setOnClickListener(this);
-
- // Build views for the current section
- for (EditEntry entry : section) {
- entry.activity = this; // this could be null from when the state is restored
- if (!entry.isDeleted) {
- View view = buildViewForEntry(entry);
- header.addView(view);
- }
- }
-
- layout.addView(header);
- }
-
- private void buildOtherViews(final LinearLayout layout, ArrayList<EditEntry> section) {
- // Build views for the current section, putting a divider between each one
- for (EditEntry entry : section) {
- View divider = mInflater.inflate(R.layout.edit_divider, layout, false);
- layout.addView(divider);
-
- entry.activity = this; // this could be null from when the state is restored
- View view = buildViewForEntry(entry);
- view.setOnClickListener(this);
- layout.addView(view);
- }
-
- View divider = mInflater.inflate(R.layout.edit_divider, layout, false);
- layout.addView(divider);
- }
-
- /**
- * Builds a view to display an EditEntry.
- *
- * @param entry the entry to display
- * @return a view that will display the given entry
- */
- /* package */ View buildViewForEntry(final EditEntry entry) {
- // Look for any existing entered text, and save it if found
- if (entry.view != null && entry.syncDataWithView) {
- String enteredText = ((TextView) entry.view.findViewById(R.id.data))
- .getText().toString();
- if (!TextUtils.isEmpty(enteredText)) {
- entry.data = enteredText;
- }
- }
-
- // Build a new view
- final ViewGroup parent = mLayout;
- View view;
-
- // Because we're emulating a ListView, we might need to handle focus changes
- // with some additional logic.
- if (entry.kind == Contacts.KIND_ORGANIZATION) {
- view = mInflater.inflate(R.layout.edit_contact_entry_org, parent, false);
- } else if (isOtherEntry(entry, People.CUSTOM_RINGTONE)) {
- view = mInflater.inflate(R.layout.edit_contact_entry_ringtone, parent, false);
- view.setOnFocusChangeListener(this);
- } else if (isOtherEntry(entry, People.SEND_TO_VOICEMAIL)) {
- view = mInflater.inflate(R.layout.edit_contact_entry_voicemail, parent, false);
- view.setOnFocusChangeListener(this);
- } else if (!entry.isStaticLabel) {
- view = mInflater.inflate(R.layout.edit_contact_entry, parent, false);
- } else {
- view = mInflater.inflate(R.layout.edit_contact_entry_static_label, parent, false);
- }
- entry.view = view;
-
- // Set the entry as the tag so we can find it again later given just the view
- view.setTag(entry);
-
- // Bind the label
- entry.bindLabel(this);
-
- // Bind data
- TextView data = (TextView) view.findViewById(R.id.data);
- TextView data2 = (TextView) view.findViewById(R.id.data2);
-
- if (data instanceof Button) {
- data.setOnClickListener(this);
- }
- if (data.length() == 0) {
- if (entry.syncDataWithView) {
- // If there is already data entered don't overwrite it
- data.setText(entry.data);
- } else {
- fillViewData(entry);
- }
- }
- if (data2 != null && data2.length() == 0) {
- // If there is already data entered don't overwrite it
- data2.setText(entry.data2);
- }
- data.setHint(entry.hint);
- if (data2 != null) data2.setHint(entry.hint2);
- if (entry.lines > 1) {
- data.setLines(entry.lines);
- data.setMaxLines(entry.maxLines);
- if (data2 != null) {
- data2.setLines(entry.lines);
- data2.setMaxLines(entry.maxLines);
- }
- }
- int contentType = entry.contentType;
- if (contentType != EditorInfo.TYPE_NULL) {
- data.setInputType(contentType);
- if (data2 != null) {
- data2.setInputType(contentType);
- }
- if ((contentType&EditorInfo.TYPE_MASK_CLASS)
- == EditorInfo.TYPE_CLASS_PHONE) {
- data.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
- if (data2 != null) {
- data2.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
- }
- }
- }
-
- // Give focus to children as requested, possibly after a configuration change
- View focusChild = view.findViewById(entry.requestFocusId);
- if (focusChild != null) {
- focusChild.requestFocus();
- if (focusChild instanceof EditText) {
- ((EditText) focusChild).setSelection(entry.requestCursor);
- }
- }
-
- // Reset requested focus values
- entry.requestFocusId = View.NO_ID;
- entry.requestCursor = 0;
-
- // Connect listeners up to watch for changed values.
- if (data instanceof EditText) {
- data.addTextChangedListener(this);
- }
- if (data2 instanceof EditText) {
- data2.addTextChangedListener(this);
- }
-
- // Hook up the delete button
- View delete = view.findViewById(R.id.delete);
- if (delete != null) delete.setOnClickListener(this);
-
- return view;
- }
-
- private void fillViewData(final EditEntry entry) {
- if (isOtherEntry(entry, People.CUSTOM_RINGTONE)) {
- updateRingtoneView(entry);
- } else if (isOtherEntry(entry, People.SEND_TO_VOICEMAIL)) {
- CheckBox checkBox = (CheckBox) entry.view.findViewById(R.id.checkbox);
- boolean sendToVoicemail = false;
- if (entry.data != null) {
- sendToVoicemail = (Integer.valueOf(entry.data) == 1);
- }
- checkBox.setChecked(sendToVoicemail);
- }
- }
-
- /**
- * Handles the results from the label change picker.
- */
- private final class LabelPickedListener implements DialogInterface.OnClickListener {
- EditEntry mEntry;
- String[] mLabels;
-
- public LabelPickedListener(EditEntry entry, String[] labels) {
- mEntry = entry;
- mLabels = labels;
- }
-
- public void onClick(DialogInterface dialog, int which) {
- // TODO: Use a managed dialog
- if (mEntry.kind != Contacts.KIND_IM) {
- final int type = getTypeFromLabelPosition(mLabels, which);
- if (type == ContactMethods.TYPE_CUSTOM) {
- createCustomPicker(mEntry, null);
- } else {
- mEntry.setLabel(EditContactActivity.this, type, mLabels[which]);
- mContactChanged = true;
- }
- } else {
- mEntry.setLabel(EditContactActivity.this, which, mLabels[which]);
- mContactChanged = true;
- }
- }
- }
-
- /**
- * A basic structure with the data for a contact entry in the list.
- */
- private static final class EditEntry extends ContactEntryAdapter.Entry implements Parcelable {
- // These aren't stuffed into the parcel
- public EditContactActivity activity;
- public View view;
-
- // These are stuffed into the parcel
- public String hint;
- public String hint2;
- public String column;
- public String contentDirectory;
- public String data2;
- public int contentType;
- public int type;
- /**
- * If 0 or 1, setSingleLine will be called. If negative, setSingleLine
- * will not be called.
- */
- public int lines = 1;
- public boolean isPrimary;
- public boolean isDeleted = false;
- public boolean isStaticLabel = false;
- public boolean syncDataWithView = true;
-
- /**
- * Request focus on the child of this {@link EditEntry} found using
- * {@link View#findViewById(int)}. This value should be reset to
- * {@link View#NO_ID} after each use.
- */
- public int requestFocusId = View.NO_ID;
-
- /**
- * If the {@link #requestFocusId} is an {@link EditText}, this value
- * indicates the requested cursor position placement.
- */
- public int requestCursor = 0;
-
- private EditEntry() {
- // only used by CREATOR
- }
-
- public EditEntry(EditContactActivity activity) {
- this.activity = activity;
- }
-
- public EditEntry(EditContactActivity activity, String label,
- int type, String data, Uri uri, long id) {
- this.activity = activity;
- this.isPrimary = false;
- this.label = label;
- this.type = type;
- this.data = data;
- this.uri = uri;
- this.id = id;
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel parcel, int flags) {
- // Make sure to read data from the input field, if anything is entered
- data = getData();
-
- // Write in our own fields.
- parcel.writeString(hint);
- parcel.writeString(hint2);
- parcel.writeString(column);
- parcel.writeString(contentDirectory);
- parcel.writeString(data2);
- parcel.writeInt(contentType);
- parcel.writeInt(type);
- parcel.writeInt(lines);
- parcel.writeInt(isPrimary ? 1 : 0);
- parcel.writeInt(isDeleted ? 1 : 0);
- parcel.writeInt(isStaticLabel ? 1 : 0);
- parcel.writeInt(syncDataWithView ? 1 : 0);
-
- // Write in the fields from Entry
- super.writeToParcel(parcel);
- }
-
- public static final Parcelable.Creator<EditEntry> CREATOR =
- new Parcelable.Creator<EditEntry>() {
- public EditEntry createFromParcel(Parcel in) {
- EditEntry entry = new EditEntry();
-
- // Read out our own fields
- entry.hint = in.readString();
- entry.hint2 = in.readString();
- entry.column = in.readString();
- entry.contentDirectory = in.readString();
- entry.data2 = in.readString();
- entry.contentType = in.readInt();
- entry.type = in.readInt();
- entry.lines = in.readInt();
- entry.isPrimary = in.readInt() == 1;
- entry.isDeleted = in.readInt() == 1;
- entry.isStaticLabel = in.readInt() == 1;
- entry.syncDataWithView = in.readInt() == 1;
-
- // Read out the fields from Entry
- entry.readFromParcel(in);
-
- return entry;
- }
-
- public EditEntry[] newArray(int size) {
- return new EditEntry[size];
- }
- };
-
- public void setLabel(Context context, int typeIn, String labelIn) {
- type = typeIn;
- label = labelIn;
- if (view != null) {
- bindLabel(context);
- }
- }
-
- public void bindLabel(Context context) {
- TextView v = (TextView) view.findViewById(R.id.label);
- if (isStaticLabel) {
- v.setText(label);
- return;
- }
-
- switch (kind) {
- case Contacts.KIND_PHONE: {
- v.setText(Phones.getDisplayLabel(context, type, label));
- break;
- }
-
- case Contacts.KIND_IM: {
- v.setText(getLabelsForKind(activity, kind)[type]);
- break;
- }
-
- case Contacts.KIND_ORGANIZATION: {
- v.setText(Organizations.getDisplayLabel(activity, type, label));
- break;
- }
-
- default: {
- v.setText(Contacts.ContactMethods.getDisplayLabel(context, kind, type, label));
- if (kind == Contacts.KIND_POSTAL) {
- v.setMaxLines(3);
- }
- break;
- }
- }
- v.setOnClickListener(activity);
- }
-
- /**
- * Returns the data for the entry
- * @return the data for the entry
- */
- public String getData() {
- if (view != null && syncDataWithView) {
- CharSequence text = ((TextView) view.findViewById(R.id.data)).getText();
- if (text != null) {
- return text.toString();
- }
- }
-
- if (data != null) {
- return data.toString();
- }
-
- return null;
- }
-
- /**
- * Dumps the entry into a HashMap suitable for passing to the database.
- *
- * @param values the HashMap to fill in.
- * @return true if the value should be saved, false otherwise
- */
- public boolean toValues(ContentValues values) {
- boolean success = false;
- String labelString = null;
- // Save the type and label
- if (view != null) {
- // Read the possibly updated label from the text field
- labelString = ((TextView) view.findViewById(R.id.label)).getText().toString();
- }
- switch (kind) {
- case Contacts.KIND_PHONE:
- if (type != Phones.TYPE_CUSTOM) {
- labelString = null;
- }
- values.put(Phones.LABEL, labelString);
- values.put(Phones.TYPE, type);
- break;
-
- case Contacts.KIND_EMAIL:
- if (type != ContactMethods.TYPE_CUSTOM) {
- labelString = null;
- }
- values.put(ContactMethods.LABEL, labelString);
- values.put(ContactMethods.KIND, kind);
- values.put(ContactMethods.TYPE, type);
- break;
-
- case Contacts.KIND_IM:
- values.put(ContactMethods.KIND, kind);
- values.put(ContactMethods.TYPE, ContactMethods.TYPE_OTHER);
- values.putNull(ContactMethods.LABEL);
- if (type != -1) {
- values.put(ContactMethods.AUX_DATA,
- ContactMethods.encodePredefinedImProtocol(type));
- } else {
- values.put(ContactMethods.AUX_DATA,
- ContactMethods.encodeCustomImProtocol(label.toString()));
- }
- break;
-
- case Contacts.KIND_POSTAL:
- if (type != ContactMethods.TYPE_CUSTOM) {
- labelString = null;
- }
- values.put(ContactMethods.LABEL, labelString);
- values.put(ContactMethods.KIND, kind);
- values.put(ContactMethods.TYPE, type);
- break;
-
- case Contacts.KIND_ORGANIZATION:
- if (type != ContactMethods.TYPE_CUSTOM) {
- labelString = null;
- }
- values.put(ContactMethods.LABEL, labelString);
- values.put(ContactMethods.TYPE, type);
- // Save the title
- if (view != null) {
- // Read the possibly updated data from the text field
- data2 = ((TextView) view.findViewById(R.id.data2)).getText().toString();
- }
- if (!TextUtils.isGraphic(data2)) {
- values.putNull(Organizations.TITLE);
- } else {
- values.put(Organizations.TITLE, data2.toString());
- success = true;
- }
- break;
-
- default:
- Log.w(TAG, "unknown kind " + kind);
- values.put(ContactMethods.LABEL, labelString);
- values.put(ContactMethods.KIND, kind);
- values.put(ContactMethods.TYPE, type);
- break;
- }
-
- // Only set the ISPRIMARY flag if part of the incoming data. This is because the
- // ContentProvider will try finding a new primary when setting to false, meaning
- // it's possible to lose primary altogether as we walk down the list. If this editor
- // implements editing of primaries in the future, this will need to be revisited.
- if (isPrimary) {
- values.put(ContactMethods.ISPRIMARY, 1);
- }
-
- // Save the data
- if (view != null && syncDataWithView) {
- // Read the possibly updated data from the text field
- data = ((TextView) view.findViewById(R.id.data)).getText().toString();
- }
- if (!TextUtils.isGraphic(data)) {
- values.putNull(column);
- return success;
- } else {
- values.put(column, data.toString());
- return true;
- }
- }
-
- /**
- * Create a new empty organization entry
- */
- public static final EditEntry newOrganizationEntry(EditContactActivity activity,
- Uri uri, int type) {
- return newOrganizationEntry(activity, null, type, null, null, uri, 0);
- }
-
- /**
- * Create a new company entry with the given data.
- */
- public static final EditEntry newOrganizationEntry(EditContactActivity activity,
- String label, int type, String company, String title, Uri uri, long id) {
- EditEntry entry = new EditEntry(activity, label, type, company, uri, id);
- entry.hint = activity.getString(R.string.ghostData_company);
- entry.hint2 = activity.getString(R.string.ghostData_title);
- entry.data2 = title;
- entry.column = Organizations.COMPANY;
- entry.contentDirectory = Organizations.CONTENT_DIRECTORY;
- entry.kind = Contacts.KIND_ORGANIZATION;
- entry.contentType = EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
- return entry;
- }
-
- /**
- * Create a new notes entry with the given data.
- */
- public static final EditEntry newNotesEntry(EditContactActivity activity,
- String data, Uri uri) {
- EditEntry entry = new EditEntry(activity);
- entry.label = activity.getString(R.string.label_notes);
- entry.hint = activity.getString(R.string.ghostData_notes);
- entry.data = data;
- entry.uri = uri;
- entry.column = People.NOTES;
- entry.maxLines = 10;
- entry.lines = 2;
- entry.id = 0;
- entry.kind = KIND_CONTACT;
- entry.contentType = EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
- | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
- entry.isStaticLabel = true;
- return entry;
- }
-
- /**
- * Create a new ringtone entry with the given data.
- */
- public static final EditEntry newRingtoneEntry(EditContactActivity activity,
- String data, Uri uri) {
- EditEntry entry = new EditEntry(activity);
- entry.label = activity.getString(R.string.label_ringtone);
- entry.data = data;
- entry.uri = uri;
- entry.column = People.CUSTOM_RINGTONE;
- entry.kind = KIND_CONTACT;
- entry.isStaticLabel = true;
- entry.syncDataWithView = false;
- entry.lines = -1;
- return entry;
- }
-
- /**
- * Create a new send-to-voicemail entry with the given data.
- */
- public static final EditEntry newSendToVoicemailEntry(EditContactActivity activity,
- String data, Uri uri) {
- EditEntry entry = new EditEntry(activity);
- entry.label = activity.getString(R.string.actionIncomingCall);
- entry.data = data;
- entry.uri = uri;
- entry.column = People.SEND_TO_VOICEMAIL;
- entry.kind = KIND_CONTACT;
- entry.isStaticLabel = true;
- entry.syncDataWithView = false;
- entry.lines = -1;
- return entry;
- }
-
- /**
- * Create a new empty email entry
- */
- public static final EditEntry newPhoneEntry(EditContactActivity activity,
- Uri uri, int type) {
- return newPhoneEntry(activity, null, type, null, uri, 0);
- }
-
- /**
- * Create a new phone entry with the given data.
- */
- public static final EditEntry newPhoneEntry(EditContactActivity activity,
- String label, int type, String data, Uri uri,
- long id) {
- EditEntry entry = new EditEntry(activity, label, type, data, uri, id);
- entry.hint = activity.getString(R.string.ghostData_phone);
- entry.column = People.Phones.NUMBER;
- entry.contentDirectory = People.Phones.CONTENT_DIRECTORY;
- entry.kind = Contacts.KIND_PHONE;
- entry.contentType = EditorInfo.TYPE_CLASS_PHONE;
- return entry;
- }
-
- /**
- * Create a new empty email entry
- */
- public static final EditEntry newEmailEntry(EditContactActivity activity,
- Uri uri, int type) {
- return newEmailEntry(activity, null, type, null, uri, 0);
- }
-
- /**
- * Create a new email entry with the given data.
- */
- public static final EditEntry newEmailEntry(EditContactActivity activity,
- String label, int type, String data, Uri uri,
- long id) {
- EditEntry entry = new EditEntry(activity, label, type, data, uri, id);
- entry.hint = activity.getString(R.string.ghostData_email);
- entry.column = ContactMethods.DATA;
- entry.contentDirectory = People.ContactMethods.CONTENT_DIRECTORY;
- entry.kind = Contacts.KIND_EMAIL;
- entry.contentType = EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
- return entry;
- }
-
- /**
- * Create a new empty postal address entry
- */
- public static final EditEntry newPostalEntry(EditContactActivity activity,
- Uri uri, int type) {
- return newPostalEntry(activity, null, type, null, uri, 0);
- }
-
- /**
- * Create a new postal address entry with the given data.
- *
- * @param label label for the item, from the db not the display label
- * @param type the type of postal address
- * @param data the starting data for the entry, may be null
- * @param uri the uri for the entry if it already exists, may be null
- * @param id the id for the entry if it already exists, 0 it it doesn't
- * @return the new EditEntry
- */
- public static final EditEntry newPostalEntry(EditContactActivity activity,
- String label, int type, String data, Uri uri, long id) {
- EditEntry entry = new EditEntry(activity, label, type, data, uri, id);
- entry.hint = activity.getString(R.string.ghostData_postal);
- entry.column = ContactMethods.DATA;
- entry.contentDirectory = People.ContactMethods.CONTENT_DIRECTORY;
- entry.kind = Contacts.KIND_POSTAL;
- entry.contentType = EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS
- | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS
- | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
- entry.maxLines = 4;
- entry.lines = 2;
- return entry;
- }
-
- /**
- * Create a new IM address entry
- */
- public static final EditEntry newImEntry(EditContactActivity activity,
- Uri uri, int type) {
- return newImEntry(activity, null, type, null, uri, 0);
- }
-
- /**
- * Create a new IM address entry with the given data.
- *
- * @param label label for the item, from the db not the display label
- * @param protocol the type used
- * @param data the starting data for the entry, may be null
- * @param uri the uri for the entry if it already exists, may be null
- * @param id the id for the entry if it already exists, 0 it it doesn't
- * @return the new EditEntry
- */
- public static final EditEntry newImEntry(EditContactActivity activity,
- String label, int protocol, String data, Uri uri, long id) {
- EditEntry entry = new EditEntry(activity, label, protocol, data, uri, id);
- entry.hint = activity.getString(R.string.ghostData_im);
- entry.column = ContactMethods.DATA;
- entry.contentDirectory = People.ContactMethods.CONTENT_DIRECTORY;
- entry.kind = Contacts.KIND_IM;
- entry.contentType = EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
- return entry;
- }
- }
-
- public void afterTextChanged(Editable s) {
- // Someone edited a text field, so assume this contact is changed
- mContactChanged = true;
- }
-
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- // Do nothing; editing handled by afterTextChanged()
- }
-
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- // Do nothing; editing handled by afterTextChanged()
- }
-
- public void onFocusChange(View v, boolean hasFocus) {
- // Because we're emulating a ListView, we need to setSelected() for
- // views as they are focused.
- v.setSelected(hasFocus);
- }
-}
diff --git a/src/com/android/contacts/ExportVCardActivity.java b/src/com/android/contacts/ExportVCardActivity.java
new file mode 100644
index 0000000..baf2371
--- /dev/null
+++ b/src/com/android/contacts/ExportVCardActivity.java
@@ -0,0 +1,454 @@
+/*
+ * 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.
+ */
+package com.android.contacts;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.pim.vcard.VCardComposer;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ExportVCardActivity extends Activity {
+ private static final String LOG_TAG = "ExportVCardActivity";
+
+ // If true, VCardExporter is able to emits files longer than 8.3 format.
+ private static final boolean ALLOW_LONG_FILE_NAME = false;
+ private String mTargetDirectory;
+ private String mFileNamePrefix;
+ private String mFileNameSuffix;
+ private int mFileIndexMinimum;
+ private int mFileIndexMaximum;
+ private String mFileNameExtension;
+ private String mVCardTypeStr;
+ private Set<String> mExtensionsToConsider;
+
+ private ProgressDialog mProgressDialog;
+ private String mExportingFileName;
+
+ private Handler mHandler = new Handler();
+
+ // Used temporaly when asking users to confirm the file name
+ private String mTargetFileName;
+
+ // String for storing error reason temporaly.
+ private String mErrorReason;
+
+ private ActualExportThread mActualExportThread;
+
+ private class CancelListener
+ implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ }
+
+ private CancelListener mCancelListener = new CancelListener();
+
+ private class ErrorReasonDisplayer implements Runnable {
+ private final int mResId;
+ public ErrorReasonDisplayer(int resId) {
+ mResId = resId;
+ }
+ public ErrorReasonDisplayer(String errorReason) {
+ mResId = R.id.dialog_fail_to_export_with_reason;
+ mErrorReason = errorReason;
+ }
+ public void run() {
+ // Show the Dialog only when the parent Activity is still alive.
+ if (!ExportVCardActivity.this.isFinishing()) {
+ showDialog(mResId);
+ }
+ }
+ }
+
+ private class ExportConfirmationListener implements DialogInterface.OnClickListener {
+ private final String mFileName;
+
+ public ExportConfirmationListener(String fileName) {
+ mFileName = fileName;
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ mActualExportThread = new ActualExportThread(mFileName);
+ mActualExportThread.start();
+ showDialog(R.id.dialog_exporting_vcard);
+ }
+ }
+ }
+
+ private class ActualExportThread extends Thread
+ implements DialogInterface.OnCancelListener {
+ private PowerManager.WakeLock mWakeLock;
+ private boolean mCanceled = false;
+
+ public ActualExportThread(String fileName) {
+ mExportingFileName = fileName;
+ PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(
+ PowerManager.SCREEN_DIM_WAKE_LOCK |
+ PowerManager.ON_AFTER_RELEASE, LOG_TAG);
+ }
+
+ @Override
+ public void run() {
+ boolean shouldCallFinish = true;
+ mWakeLock.acquire();
+ VCardComposer composer = null;
+ try {
+ OutputStream outputStream = null;
+ try {
+ outputStream = new FileOutputStream(mExportingFileName);
+ } catch (FileNotFoundException e) {
+ final String errorReason =
+ getString(R.string.fail_reason_could_not_open_file,
+ mExportingFileName, e.getMessage());
+ shouldCallFinish = false;
+ mHandler.post(new ErrorReasonDisplayer(errorReason));
+ return;
+ }
+
+ composer = new VCardComposer(ExportVCardActivity.this, mVCardTypeStr, true);
+ /*int vcardType = (VCardConfig.VCARD_TYPE_V21_GENERIC |
+ VCardConfig.FLAG_USE_QP_TO_PRIMARY_PROPERTIES);
+ composer = new VCardComposer(ExportVCardActivity.this, vcardType, true);*/
+
+ composer.addHandler(composer.new HandlerForOutputStream(outputStream));
+
+ if (!composer.init()) {
+ final String errorReason = composer.getErrorReason();
+ Log.e(LOG_TAG, "initialization of vCard composer failed: " + errorReason);
+ final String translatedErrorReason =
+ translateComposerError(errorReason);
+ mHandler.post(new ErrorReasonDisplayer(
+ getString(R.string.fail_reason_could_not_initialize_exporter,
+ translatedErrorReason)));
+ shouldCallFinish = false;
+ return;
+ }
+
+ int size = composer.getCount();
+
+ if (size == 0) {
+ mHandler.post(new ErrorReasonDisplayer(
+ getString(R.string.fail_reason_no_exportable_contact)));
+ shouldCallFinish = false;
+ return;
+ }
+
+ mProgressDialog.setProgressNumberFormat(
+ getString(R.string.exporting_contact_list_progress));
+ mProgressDialog.setMax(size);
+ mProgressDialog.setProgress(0);
+
+ while (!composer.isAfterLast()) {
+ if (mCanceled) {
+ return;
+ }
+ if (!composer.createOneEntry()) {
+ final String errorReason = composer.getErrorReason();
+ Log.e(LOG_TAG, "Failed to read a contact: " + errorReason);
+ final String translatedErrorReason =
+ translateComposerError(errorReason);
+ mHandler.post(new ErrorReasonDisplayer(
+ getString(R.string.fail_reason_error_occurred_during_export,
+ translatedErrorReason)));
+ shouldCallFinish = false;
+ return;
+ }
+ mProgressDialog.incrementProgressBy(1);
+ }
+ } finally {
+ if (composer != null) {
+ composer.terminate();
+ }
+ mWakeLock.release();
+ mProgressDialog.dismiss();
+ if (shouldCallFinish && !isFinishing()) {
+ finish();
+ }
+ }
+ }
+
+ @Override
+ public void finalize() {
+ if (mWakeLock != null && mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ }
+
+ public void cancel() {
+ mCanceled = true;
+ }
+
+ public void onCancel(DialogInterface dialog) {
+ cancel();
+ }
+ }
+
+ private String translateComposerError(String errorMessage) {
+ Resources resources = getResources();
+ if (VCardComposer.FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO.equals(errorMessage)) {
+ return resources.getString(R.string.composer_failed_to_get_database_infomation);
+ } else if (VCardComposer.FAILURE_REASON_NO_ENTRY.equals(errorMessage)) {
+ return resources.getString(R.string.composer_has_no_exportable_contact);
+ } else if (VCardComposer.FAILURE_REASON_NOT_INITIALIZED.equals(errorMessage)) {
+ return resources.getString(R.string.composer_not_initialized);
+ } else {
+ return errorMessage;
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ mTargetDirectory = getString(R.string.config_export_dir);
+ mFileNamePrefix = getString(R.string.config_export_file_prefix);
+ mFileNameSuffix = getString(R.string.config_export_file_suffix);
+ mFileNameExtension = getString(R.string.config_export_file_extension);
+ mVCardTypeStr = getString(R.string.config_export_vcard_type);
+
+ mExtensionsToConsider = new HashSet<String>();
+ mExtensionsToConsider.add(mFileNameExtension);
+
+ final String additionalExtensions =
+ getString(R.string.config_export_extensions_to_consider);
+ if (!TextUtils.isEmpty(additionalExtensions)) {
+ for (String extension : additionalExtensions.split(",")) {
+ String trimed = extension.trim();
+ if (trimed.length() > 0) {
+ mExtensionsToConsider.add(trimed);
+ }
+ }
+ }
+
+ final Resources resources = getResources();
+ mFileIndexMinimum = resources.getInteger(R.integer.config_export_file_min_index);
+ mFileIndexMaximum = resources.getInteger(R.integer.config_export_file_max_index);
+
+ startExportVCardToSdCard();
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case R.id.dialog_export_confirmation: {
+ return getExportConfirmationDialog();
+ }
+ case R.string.fail_reason_too_many_vcard: {
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.exporting_contact_failed_title)
+ .setMessage(getString(R.string.exporting_contact_failed_message,
+ getString(R.string.fail_reason_too_many_vcard)))
+ .setPositiveButton(android.R.string.ok, mCancelListener)
+ .create();
+ }
+ case R.id.dialog_fail_to_export_with_reason: {
+ return getErrorDialogWithReason();
+ }
+ case R.id.dialog_sdcard_not_found: {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(R.string.no_sdcard_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.no_sdcard_message)
+ .setPositiveButton(android.R.string.ok, mCancelListener);
+ return builder.create();
+ }
+ case R.id.dialog_exporting_vcard: {
+ return getExportingVCardDialog();
+ }
+ }
+ return super.onCreateDialog(id);
+ }
+
+ private Dialog getExportingVCardDialog() {
+ if (mProgressDialog == null) {
+ String title = getString(R.string.exporting_contact_list_title);
+ String message = getString(R.string.exporting_contact_list_message,
+ mExportingFileName);
+ mProgressDialog = new ProgressDialog(ExportVCardActivity.this);
+ mProgressDialog.setTitle(title);
+ mProgressDialog.setMessage(message);
+ mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ mProgressDialog.setOnCancelListener(mActualExportThread);
+ }
+ return mProgressDialog;
+ }
+
+ @Override
+ protected void onPrepareDialog(int id, Dialog dialog) {
+ if (id == R.id.dialog_fail_to_export_with_reason) {
+ ((AlertDialog)dialog).setMessage(getErrorReason());
+ } else if (id == R.id.dialog_export_confirmation) {
+ ((AlertDialog)dialog).setMessage(
+ getString(R.string.confirm_export_message, mTargetFileName));
+ } else {
+ super.onPrepareDialog(id, dialog);
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (mActualExportThread != null) {
+ // The Activity is no longer visible. Stop the thread.
+ mActualExportThread.cancel();
+ mActualExportThread = null;
+ }
+
+ if (!isFinishing()) {
+ finish();
+ }
+ }
+
+ /**
+ * Tries to start exporting VCard. If there's no SDCard available,
+ * an error dialog is shown.
+ */
+ public void startExportVCardToSdCard() {
+ File targetDirectory = new File(mTargetDirectory);
+
+ if (!(targetDirectory.exists() &&
+ targetDirectory.isDirectory() &&
+ targetDirectory.canRead()) &&
+ !targetDirectory.mkdirs()) {
+ showDialog(R.id.dialog_sdcard_not_found);
+ } else {
+ mTargetFileName = getAppropriateFileName(mTargetDirectory);
+ if (TextUtils.isEmpty(mTargetFileName)) {
+ mTargetFileName = null;
+ // finish() is called via the error dialog. Do not call the method here.
+ return;
+ }
+
+ showDialog(R.id.dialog_export_confirmation);
+ }
+ }
+
+ /**
+ * Tries to get an appropriate filename. Returns null if it fails.
+ */
+ private String getAppropriateFileName(final String destDirectory) {
+ int fileNumberStringLength = 0;
+ {
+ // Calling Math.Log10() is costly.
+ int tmp;
+ for (fileNumberStringLength = 0, tmp = mFileIndexMaximum; tmp > 0;
+ fileNumberStringLength++, tmp /= 10) {
+ }
+ }
+ String bodyFormat = "%s%0" + fileNumberStringLength + "d%s";
+
+ if (!ALLOW_LONG_FILE_NAME) {
+ String possibleBody = String.format(bodyFormat,mFileNamePrefix, 1, mFileNameSuffix);
+ if (possibleBody.length() > 8 || mFileNameExtension.length() > 3) {
+ Log.e(LOG_TAG, "This code does not allow any long file name.");
+ mErrorReason = getString(R.string.fail_reason_too_long_filename,
+ String.format("%s.%s", possibleBody, mFileNameExtension));
+ showDialog(R.id.dialog_fail_to_export_with_reason);
+ // finish() is called via the error dialog. Do not call the method here.
+ return null;
+ }
+ }
+
+ // Note that this logic assumes that the target directory is case insensitive.
+ // As of 2009-07-16, it is true since the external storage is only sdcard, and
+ // it is formated as FAT/VFAT.
+ // TODO: fix this.
+ for (int i = mFileIndexMinimum; i <= mFileIndexMaximum; i++) {
+ boolean numberIsAvailable = true;
+ // SD Association's specification seems to require this feature, though we cannot
+ // have the specification since it is proprietary...
+ String body = null;
+ for (String possibleExtension : mExtensionsToConsider) {
+ body = String.format(bodyFormat, mFileNamePrefix, i, mFileNameSuffix);
+ File file = new File(String.format("%s/%s.%s",
+ destDirectory, body, possibleExtension));
+ if (file.exists()) {
+ numberIsAvailable = false;
+ break;
+ }
+ }
+ if (numberIsAvailable) {
+ return String.format("%s/%s.%s", destDirectory, body, mFileNameExtension);
+ }
+ }
+ showDialog(R.string.fail_reason_too_many_vcard);
+ return null;
+ }
+
+ public Dialog getExportConfirmationDialog() {
+ if (TextUtils.isEmpty(mTargetFileName)) {
+ Log.e(LOG_TAG, "Target file name is empty, which must not be!");
+ // This situation is not acceptable (probably a bug!), but we don't have no reason to
+ // show...
+ mErrorReason = null;
+ return getErrorDialogWithReason();
+ }
+
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.confirm_export_title)
+ .setMessage(getString(R.string.confirm_export_message, mTargetFileName))
+ .setPositiveButton(android.R.string.ok,
+ new ExportConfirmationListener(mTargetFileName))
+ .setNegativeButton(android.R.string.cancel, mCancelListener)
+ .setOnCancelListener(mCancelListener)
+ .create();
+ }
+
+ public Dialog getErrorDialogWithReason() {
+ if (mErrorReason == null) {
+ Log.e(LOG_TAG, "Error reason must have been set.");
+ mErrorReason = getString(R.string.fail_reason_unknown);
+ }
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.exporting_contact_failed_title)
+ .setMessage(getString(R.string.exporting_contact_failed_message, mErrorReason))
+ .setPositiveButton(android.R.string.ok, mCancelListener)
+ .setOnCancelListener(mCancelListener)
+ .create();
+ }
+
+ public void cancelExport() {
+ if (mActualExportThread != null) {
+ mActualExportThread.cancel();
+ mActualExportThread = null;
+ }
+ }
+
+ public String getErrorReason() {
+ return mErrorReason;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/FocusRequestingListView.java b/src/com/android/contacts/FocusRequestingListView.java
new file mode 100644
index 0000000..7461d70
--- /dev/null
+++ b/src/com/android/contacts/FocusRequestingListView.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ListView;
+
+/* Subclass of ListView that requests focus after it is layed out for the first time. */
+public class FocusRequestingListView extends ListView {
+
+ private boolean mFirstLayoutDone = false;
+
+ public FocusRequestingListView(Context context) {
+ super(context);
+ }
+
+ public FocusRequestingListView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public FocusRequestingListView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (!mFirstLayoutDone) {
+ setFocusable(true);
+ requestFocus();
+ }
+ mFirstLayoutDone = true;
+ }
+}
diff --git a/src/com/android/contacts/ImportVCardActivity.java b/src/com/android/contacts/ImportVCardActivity.java
index 07eb821..8fd9c0d 100644
--- a/src/com/android/contacts/ImportVCardActivity.java
+++ b/src/com/android/contacts/ImportVCardActivity.java
@@ -16,30 +16,36 @@
package com.android.contacts;
+import android.accounts.Account;
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
-import android.syncml.pim.VBuilder;
-import android.syncml.pim.VBuilderCollection;
-import android.syncml.pim.VParser;
-import android.syncml.pim.vcard.VCardDataBuilder;
-import android.syncml.pim.vcard.VCardEntryCounter;
-import android.syncml.pim.vcard.VCardException;
-import android.syncml.pim.vcard.VCardNestedException;
-import android.syncml.pim.vcard.VCardParser_V21;
-import android.syncml.pim.vcard.VCardParser_V30;
-import android.syncml.pim.vcard.VCardSourceDetector;
-import android.syncml.pim.vcard.VCardVersionException;
+import android.pim.vcard.EntryCommitter;
+import android.pim.vcard.VCardBuilder;
+import android.pim.vcard.VCardBuilderCollection;
+import android.pim.vcard.VCardConfig;
+import android.pim.vcard.VCardDataBuilder;
+import android.pim.vcard.VCardEntryCounter;
+import android.pim.vcard.VCardParser_V21;
+import android.pim.vcard.VCardParser_V30;
+import android.pim.vcard.VCardSourceDetector;
+import android.pim.vcard.exception.VCardException;
+import android.pim.vcard.exception.VCardNestedException;
+import android.pim.vcard.exception.VCardNotSupportedException;
+import android.pim.vcard.exception.VCardVersionException;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
+import android.text.TextUtils;
import android.text.style.RelativeSizeSpan;
import android.util.Log;
@@ -48,10 +54,12 @@
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Set;
import java.util.Vector;
@@ -87,9 +95,34 @@
private static final String LOG_TAG = "ImportVCardActivity";
private static final boolean DO_PERFORMANCE_PROFILE = false;
- private ProgressDialog mProgressDialog;
private Handler mHandler = new Handler();
- private boolean mLastNameComesBeforeFirstName;
+ private Account mAccount;
+
+ private ProgressDialog mProgressDialogForScanVCard;
+
+ private List<VCardFile> mAllVCardFileList;
+ private VCardScanThread mVCardScanThread;
+ private VCardReadThread mVCardReadThread;
+ private ProgressDialog mProgressDialogForReadVCard;
+
+ private String mErrorMessage;
+
+ private class DialogDisplayer implements Runnable {
+ private final int mResId;
+ public DialogDisplayer(int resId) {
+ mResId = resId;
+ }
+ public DialogDisplayer(String errorMessage) {
+ mResId = R.id.dialog_error_with_message;
+ mErrorMessage = errorMessage;
+ }
+ public void run() {
+ // Show the Dialog only when the parent Activity is still alive.
+ if (!ImportVCardActivity.this.isFinishing()) {
+ showDialog(mResId);
+ }
+ }
+ }
private class CancelListener
implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
@@ -104,45 +137,26 @@
private CancelListener mCancelListener = new CancelListener();
- private class ErrorDisplayer implements Runnable {
- private String mErrorMessage;
-
- public ErrorDisplayer(String errorMessage) {
- mErrorMessage = errorMessage;
- }
-
- public void run() {
- String message =
- getString(R.string.reading_vcard_failed_message, mErrorMessage);
- AlertDialog.Builder builder =
- new AlertDialog.Builder(ImportVCardActivity.this)
- .setTitle(getString(R.string.reading_vcard_failed_title))
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(message)
- .setOnCancelListener(mCancelListener)
- .setPositiveButton(android.R.string.ok, mCancelListener);
- builder.show();
- }
- }
-
private class VCardReadThread extends Thread
implements DialogInterface.OnCancelListener {
- private String mCanonicalPath;
- private List<VCardFile> mVCardFileList;
private ContentResolver mResolver;
private VCardParser_V21 mVCardParser;
private boolean mCanceled;
private PowerManager.WakeLock mWakeLock;
+ private String mCanonicalPath;
+
+ private List<VCardFile> mSelectedVCardFileList;
+ private List<String> mErrorFileNameList;
public VCardReadThread(String canonicalPath) {
mCanonicalPath = canonicalPath;
- mVCardFileList = null;
init();
}
- public VCardReadThread(List<VCardFile> vcardFileList) {
+ public VCardReadThread(final List<VCardFile> selectedVCardFileList) {
mCanonicalPath = null;
- mVCardFileList = vcardFileList;
+ mSelectedVCardFileList = selectedVCardFileList;
+ mErrorFileNameList = new ArrayList<String>();
init();
}
@@ -165,35 +179,37 @@
@Override
public void run() {
+ boolean shouldCallFinish = true;
mWakeLock.acquire();
// Some malicious vCard data may make this thread broken
// (e.g. OutOfMemoryError).
// Even in such cases, some should be done.
try {
- if (mCanonicalPath != null) {
- mProgressDialog.setProgressNumberFormat("");
- mProgressDialog.setProgress(0);
+ if (mCanonicalPath != null) { // Read one file
+ mProgressDialogForReadVCard.setProgressNumberFormat("");
+ mProgressDialogForReadVCard.setProgress(0);
// Count the number of VCard entries
- mProgressDialog.setIndeterminate(true);
+ mProgressDialogForReadVCard.setIndeterminate(true);
long start;
if (DO_PERFORMANCE_PROFILE) {
start = System.currentTimeMillis();
}
VCardEntryCounter counter = new VCardEntryCounter();
VCardSourceDetector detector = new VCardSourceDetector();
- VBuilderCollection builderCollection = new VBuilderCollection(
+ VCardBuilderCollection builderCollection = new VCardBuilderCollection(
Arrays.asList(counter, detector));
+
boolean result;
try {
- result = readOneVCard(mCanonicalPath,
- VParser.DEFAULT_CHARSET, builderCollection, null, true);
+ result = readOneVCardFile(mCanonicalPath,
+ VCardConfig.DEFAULT_CHARSET, builderCollection, null, true, null);
} catch (VCardNestedException e) {
try {
// Assume that VCardSourceDetector was able to detect the source.
// Try again with the detector.
- result = readOneVCard(mCanonicalPath,
- VParser.DEFAULT_CHARSET, counter, detector, false);
+ result = readOneVCardFile(mCanonicalPath,
+ VCardConfig.DEFAULT_CHARSET, counter, detector, false, null);
} catch (VCardNestedException e2) {
result = false;
Log.e(LOG_TAG, "Must not reach here. " + e2);
@@ -205,21 +221,24 @@
time + " ms");
}
if (!result) {
+ shouldCallFinish = false;
return;
}
- mProgressDialog.setProgressNumberFormat(
+ mProgressDialogForReadVCard.setProgressNumberFormat(
getString(R.string.reading_vcard_contacts));
- mProgressDialog.setIndeterminate(false);
- mProgressDialog.setMax(counter.getCount());
+ mProgressDialogForReadVCard.setIndeterminate(false);
+ mProgressDialogForReadVCard.setMax(counter.getCount());
String charset = detector.getEstimatedCharset();
- doActuallyReadOneVCard(charset, true, detector);
- } else {
- mProgressDialog.setProgressNumberFormat(
+ doActuallyReadOneVCard(mCanonicalPath, null, charset, true, detector,
+ mErrorFileNameList);
+ } else { // Read multiple files.
+ mProgressDialogForReadVCard.setProgressNumberFormat(
getString(R.string.reading_vcard_files));
- mProgressDialog.setMax(mVCardFileList.size());
- mProgressDialog.setProgress(0);
- for (VCardFile vcardFile : mVCardFileList) {
+ mProgressDialogForReadVCard.setMax(mSelectedVCardFileList.size());
+ mProgressDialogForReadVCard.setProgress(0);
+
+ for (VCardFile vcardFile : mSelectedVCardFileList) {
if (mCanceled) {
return;
}
@@ -227,66 +246,81 @@
VCardSourceDetector detector = new VCardSourceDetector();
try {
- if (!readOneVCard(canonicalPath, VParser.DEFAULT_CHARSET, detector,
- null, true)) {
+ if (!readOneVCardFile(canonicalPath, VCardConfig.DEFAULT_CHARSET,
+ detector, null, true, mErrorFileNameList)) {
continue;
}
} catch (VCardNestedException e) {
// Assume that VCardSourceDetector was able to detect the source.
}
String charset = detector.getEstimatedCharset();
- doActuallyReadOneVCard(charset, false, detector);
- mProgressDialog.incrementProgressBy(1);
+ doActuallyReadOneVCard(canonicalPath, mAccount,
+ charset, false, detector, mErrorFileNameList);
+ mProgressDialogForReadVCard.incrementProgressBy(1);
}
}
} finally {
mWakeLock.release();
- mProgressDialog.dismiss();
- finish();
- }
- }
-
- private void doActuallyReadOneVCard(String charset, boolean doIncrementProgress,
- VCardSourceDetector detector) {
- VCardDataBuilder builder;
- final Context context = ImportVCardActivity.this;
- if (charset != null) {
- builder = new VCardDataBuilder(mResolver,
- mProgressDialog,
- context.getString(R.string.reading_vcard_message),
- mHandler,
- charset,
- charset,
- false,
- mLastNameComesBeforeFirstName);
- } else {
- builder = new VCardDataBuilder(mResolver,
- mProgressDialog,
- context.getString(R.string.reading_vcard_message),
- mHandler,
- null,
- null,
- false,
- mLastNameComesBeforeFirstName);
- charset = VParser.DEFAULT_CHARSET;
- }
- if (doIncrementProgress) {
- builder.setOnProgressRunnable(new Runnable() {
- public void run() {
- mProgressDialog.incrementProgressBy(1);
+ mProgressDialogForReadVCard.dismiss();
+ // finish() is called via mCancelListener, which is used in DialogDisplayer.
+ if (shouldCallFinish && !isFinishing()) {
+ if (mErrorFileNameList == null || mErrorFileNameList.isEmpty()) {
+ finish();
+ } else {
+ StringBuilder builder = new StringBuilder();
+ boolean first = true;
+ for (String fileName : mErrorFileNameList) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(", ");
+ }
+ builder.append(fileName);
+ }
+
+ mHandler.post(new DialogDisplayer(
+ getString(R.string.fail_reason_failed_to_read_files,
+ builder.toString())));
}
- });
+ }
}
- try {
- readOneVCard(mCanonicalPath, charset, builder, detector, false);
- } catch (VCardNestedException e) {
- Log.e(LOG_TAG, "Must not reach here.");
- }
- builder.showDebugInfo();
}
- private boolean readOneVCard(String canonicalPath, String charset, VBuilder builder,
- VCardSourceDetector detector, boolean throwNestedException)
+ private boolean doActuallyReadOneVCard(String canonicalPath, Account account,
+ String charset, boolean showEntryParseProgress,
+ VCardSourceDetector detector, List<String> errorFileNameList) {
+ final Context context = ImportVCardActivity.this;
+ VCardDataBuilder builder;
+ final String currentLanguage = Locale.getDefault().getLanguage();
+ int vcardType = VCardConfig.getVCardTypeFromString(
+ context.getString(R.string.config_import_vcard_type));
+ if (charset != null) {
+ builder = new VCardDataBuilder(charset, charset, false, vcardType, mAccount);
+ } else {
+ charset = VCardConfig.DEFAULT_CHARSET;
+ builder = new VCardDataBuilder(null, null, false, vcardType, mAccount);
+ }
+ builder.addEntryHandler(new EntryCommitter(mResolver));
+ if (showEntryParseProgress) {
+ builder.addEntryHandler(new ProgressShower(mProgressDialogForReadVCard,
+ context.getString(R.string.reading_vcard_message),
+ ImportVCardActivity.this,
+ mHandler));
+ }
+
+ try {
+ if (!readOneVCardFile(canonicalPath, charset, builder, detector, false, null)) {
+ return false;
+ }
+ } catch (VCardNestedException e) {
+ Log.e(LOG_TAG, "Never reach here.");
+ }
+ return true;
+ }
+
+ private boolean readOneVCardFile(String canonicalPath, String charset,
+ VCardBuilder builder, VCardSourceDetector detector,
+ boolean throwNestedException, List<String> errorFileNameList)
throws VCardNestedException {
FileInputStream is;
try {
@@ -316,63 +350,77 @@
}
}
}
- mVCardParser.showDebugInfo();
} catch (IOException e) {
- Log.e(LOG_TAG, "IOException was emitted: " + e);
+ Log.e(LOG_TAG, "IOException was emitted: " + e.getMessage());
- mProgressDialog.dismiss();
+ mProgressDialogForReadVCard.dismiss();
- mHandler.post(new ErrorDisplayer(
- getString(R.string.fail_reason_io_error) +
- " (" + e.getMessage() + ")"));
- return false;
- } catch (VCardNestedException e) {
- if (throwNestedException) {
- throw e;
+ if (errorFileNameList != null) {
+ errorFileNameList.add(canonicalPath);
} else {
- Log.e(LOG_TAG, "VCardNestedException was emitted: " + e);
- mHandler.post(new ErrorDisplayer(
+ mHandler.post(new DialogDisplayer(
+ getString(R.string.fail_reason_io_error) +
+ ": " + e.getLocalizedMessage()));
+ }
+ return false;
+ } catch (VCardNotSupportedException e) {
+ if ((e instanceof VCardNestedException) && throwNestedException) {
+ throw (VCardNestedException)e;
+ }
+ if (errorFileNameList != null) {
+ errorFileNameList.add(canonicalPath);
+ } else {
+ mHandler.post(new DialogDisplayer(
+ getString(R.string.fail_reason_vcard_not_supported_error) +
+ " (" + e.getMessage() + ")"));
+ }
+ return false;
+ } catch (VCardException e) {
+ if (errorFileNameList != null) {
+ errorFileNameList.add(canonicalPath);
+ } else {
+ mHandler.post(new DialogDisplayer(
getString(R.string.fail_reason_vcard_parse_error) +
" (" + e.getMessage() + ")"));
- return false;
}
- } catch (VCardException e) {
- Log.e(LOG_TAG, "VCardException was emitted: " + e);
-
- mHandler.post(new ErrorDisplayer(
- getString(R.string.fail_reason_vcard_parse_error) +
- " (" + e.getMessage() + ")"));
return false;
}
return true;
}
- public void onCancel(DialogInterface dialog) {
+ public void cancel() {
mCanceled = true;
if (mVCardParser != null) {
mVCardParser.cancel();
}
}
+
+ public void onCancel(DialogInterface dialog) {
+ cancel();
+ }
}
private class ImportTypeSelectedListener implements
DialogInterface.OnClickListener {
- public static final int IMPORT_ALL = 0;
- public static final int IMPORT_ONE = 1;
-
- private List<VCardFile> mVCardFileList;
+ public static final int IMPORT_ONE = 0;
+ public static final int IMPORT_MULTIPLE = 1;
+ public static final int IMPORT_ALL = 2;
+ public static final int IMPORT_TYPE_SIZE = 3;
+
private int mCurrentIndex;
- public ImportTypeSelectedListener(List<VCardFile> vcardFileList) {
- mVCardFileList = vcardFileList;
- }
-
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
- if (mCurrentIndex == IMPORT_ALL) {
- importAllVCardFromSDCard(mVCardFileList);
- } else {
- showVCardFileSelectDialog(mVCardFileList);
+ switch (mCurrentIndex) {
+ case IMPORT_ALL:
+ importMultipleVCardFromSDCard(mAllVCardFileList);
+ break;
+ case IMPORT_MULTIPLE:
+ showDialog(R.id.dialog_select_multiple_vcard);
+ break;
+ default:
+ showDialog(R.id.dialog_select_one_vcard);
+ break;
}
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
finish();
@@ -381,24 +429,55 @@
}
}
}
-
- private class VCardSelectedListener implements DialogInterface.OnClickListener {
- private List<VCardFile> mVCardFileList;
+
+ private class VCardSelectedListener implements
+ DialogInterface.OnClickListener, DialogInterface.OnMultiChoiceClickListener {
private int mCurrentIndex;
+ private Set<Integer> mSelectedIndexSet;
- public VCardSelectedListener(List<VCardFile> vcardFileList) {
- mVCardFileList = vcardFileList;
+ public VCardSelectedListener(boolean multipleSelect) {
mCurrentIndex = 0;
+ if (multipleSelect) {
+ mSelectedIndexSet = new HashSet<Integer>();
+ }
}
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
- importOneVCardFromSDCard(mVCardFileList.get(mCurrentIndex).getCanonicalPath());
+ if (mSelectedIndexSet != null) {
+ List<VCardFile> selectedVCardFileList = new ArrayList<VCardFile>();
+ int size = mAllVCardFileList.size();
+ // We'd like to sort the files by its index, so we do not use Set iterator.
+ for (int i = 0; i < size; i++) {
+ if (mSelectedIndexSet.contains(i)) {
+ selectedVCardFileList.add(mAllVCardFileList.get(i));
+ }
+ }
+ importMultipleVCardFromSDCard(selectedVCardFileList);
+ } else {
+ importOneVCardFromSDCard(mAllVCardFileList.get(mCurrentIndex).getCanonicalPath());
+ }
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
finish();
} else {
// Some file is selected.
mCurrentIndex = which;
+ if (mSelectedIndexSet != null) {
+ if (mSelectedIndexSet.contains(which)) {
+ mSelectedIndexSet.remove(which);
+ } else {
+ mSelectedIndexSet.add(which);
+ }
+ }
+ }
+ }
+
+ public void onClick(DialogInterface dialog, int which, boolean isChecked) {
+ if (mSelectedIndexSet == null || (mSelectedIndexSet.contains(which) == isChecked)) {
+ Log.e(LOG_TAG, String.format("Inconsist state in index %d (%s)", which,
+ mAllVCardFileList.get(which).getCanonicalPath()));
+ } else {
+ onClick(dialog, which);
}
}
}
@@ -412,9 +491,6 @@
private boolean mGotIOException;
private File mRootDirectory;
- // null when search operation is canceled.
- private List<VCardFile> mVCardFiles;
-
// To avoid recursive link.
private Set<String> mCheckedPaths;
private PowerManager.WakeLock mWakeLock;
@@ -427,7 +503,6 @@
mGotIOException = false;
mRootDirectory = sdcardDirectory;
mCheckedPaths = new HashSet<String>();
- mVCardFiles = new Vector<VCardFile>();
PowerManager powerManager = (PowerManager)ImportVCardActivity.this.getSystemService(
Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(
@@ -437,6 +512,7 @@
@Override
public void run() {
+ mAllVCardFileList = new Vector<VCardFile>();
try {
mWakeLock.acquire();
getVCardFileRecursively(mRootDirectory);
@@ -449,59 +525,24 @@
}
if (mCanceled) {
- mVCardFiles = null;
+ mAllVCardFileList = null;
}
- mProgressDialog.dismiss();
+ mProgressDialogForScanVCard.dismiss();
+ mProgressDialogForScanVCard = null;
if (mGotIOException) {
- mHandler.post(new Runnable() {
- public void run() {
- String message = (getString(R.string.scanning_sdcard_failed_message,
- getString(R.string.fail_reason_io_error)));
-
- AlertDialog.Builder builder =
- new AlertDialog.Builder(ImportVCardActivity.this)
- .setTitle(R.string.scanning_sdcard_failed_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(message)
- .setOnCancelListener(mCancelListener)
- .setPositiveButton(android.R.string.ok, mCancelListener);
- builder.show();
- }
- });
+ mHandler.post(new DialogDisplayer(R.id.dialog_io_exception));
} else if (mCanceled) {
finish();
} else {
- mHandler.post(new Runnable() {
- public void run() {
- int size = mVCardFiles.size();
- final Context context = ImportVCardActivity.this;
- if (size == 0) {
- String message = (getString(R.string.scanning_sdcard_failed_message,
- getString(R.string.fail_reason_no_vcard_file)));
-
- AlertDialog.Builder builder =
- new AlertDialog.Builder(context)
- .setTitle(R.string.scanning_sdcard_failed_title)
- .setMessage(message)
- .setOnCancelListener(mCancelListener)
- .setPositiveButton(android.R.string.ok, mCancelListener);
- builder.show();
- return;
- } else if (context.getResources().getBoolean(
- R.bool.config_import_all_vcard_from_sdcard_automatically)) {
- importAllVCardFromSDCard(mVCardFiles);
- } else if (size == 1) {
- importOneVCardFromSDCard(mVCardFiles.get(0).getCanonicalPath());
- } else if (context.getResources().getBoolean(
- R.bool.config_allow_users_select_all_vcard_import)) {
- showSelectImportTypeDialog(mVCardFiles);
- } else {
- showVCardFileSelectDialog(mVCardFiles);
- }
- }
- });
+ int size = mAllVCardFileList.size();
+ final Context context = ImportVCardActivity.this;
+ if (size == 0) {
+ mHandler.post(new DialogDisplayer(R.id.dialog_vcard_not_found));
+ } else {
+ startVCardSelectAndImport();
+ }
}
}
@@ -529,7 +570,7 @@
String fileName = file.getName();
VCardFile vcardFile = new VCardFile(
fileName, canonicalPath, file.lastModified());
- mVCardFiles.add(vcardFile);
+ mAllVCardFileList.add(vcardFile);
}
}
}
@@ -545,43 +586,60 @@
}
}
+ private void startVCardSelectAndImport() {
+ int size = mAllVCardFileList.size();
+ if (getResources().getBoolean(R.bool.config_import_all_vcard_from_sdcard_automatically)) {
+ importMultipleVCardFromSDCard(mAllVCardFileList);
+ } else if (size == 1) {
+ importOneVCardFromSDCard(mAllVCardFileList.get(0).getCanonicalPath());
+ } else if (getResources().getBoolean(R.bool.config_allow_users_select_all_vcard_import)) {
+ mHandler.post(new DialogDisplayer(R.id.dialog_select_import_type));
+ } else {
+ mHandler.post(new DialogDisplayer(R.id.dialog_select_one_vcard));
+ }
+ }
- private void importOneVCardFromSDCard(String canonicalPath) {
- VCardReadThread thread = new VCardReadThread(canonicalPath);
- showReadingVCardDialog(thread);
- thread.start();
+ private void importMultipleVCardFromSDCard(final List<VCardFile> selectedVCardFileList) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ mVCardReadThread = new VCardReadThread(selectedVCardFileList);
+ showDialog(R.id.dialog_reading_vcard);
+ }
+ });
}
- private void importAllVCardFromSDCard(List<VCardFile> vcardFileList) {
- VCardReadThread thread = new VCardReadThread(vcardFileList);
- showReadingVCardDialog(thread);
- thread.start();
+ private void importOneVCardFromSDCard(final String canonicalPath) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ mVCardReadThread = new VCardReadThread(canonicalPath);
+ showDialog(R.id.dialog_reading_vcard);
+ }
+ });
}
- private void showSelectImportTypeDialog(List<VCardFile> vcardFileList) {
+ private Dialog getSelectImportTypeDialog() {
DialogInterface.OnClickListener listener =
- new ImportTypeSelectedListener(vcardFileList);
- AlertDialog.Builder builder =
- new AlertDialog.Builder(ImportVCardActivity.this)
- .setTitle(R.string.select_vcard_title)
- .setPositiveButton(android.R.string.ok, listener)
- .setOnCancelListener(mCancelListener)
- .setNegativeButton(android.R.string.cancel, mCancelListener);
+ new ImportTypeSelectedListener();
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(R.string.select_vcard_title)
+ .setPositiveButton(android.R.string.ok, listener)
+ .setOnCancelListener(mCancelListener)
+ .setNegativeButton(android.R.string.cancel, mCancelListener);
- String[] items = new String[2];
- items[ImportTypeSelectedListener.IMPORT_ALL] =
- getString(R.string.import_all_vcard_string);
+ String[] items = new String[ImportTypeSelectedListener.IMPORT_TYPE_SIZE];
items[ImportTypeSelectedListener.IMPORT_ONE] =
getString(R.string.import_one_vcard_string);
- builder.setSingleChoiceItems(items,
- ImportTypeSelectedListener.IMPORT_ALL, listener);
- builder.show();
+ items[ImportTypeSelectedListener.IMPORT_MULTIPLE] =
+ getString(R.string.import_multiple_vcard_string);
+ items[ImportTypeSelectedListener.IMPORT_ALL] =
+ getString(R.string.import_all_vcard_string);
+ builder.setSingleChoiceItems(items, ImportTypeSelectedListener.IMPORT_ONE, listener);
+ return builder.create();
}
- private void showVCardFileSelectDialog(List<VCardFile> vcardFileList) {
- int size = vcardFileList.size();
- DialogInterface.OnClickListener listener =
- new VCardSelectedListener(vcardFileList);
+ private Dialog getVCardFileSelectDialog(boolean multipleSelect) {
+ int size = mAllVCardFileList.size();
+ VCardSelectedListener listener = new VCardSelectedListener(multipleSelect);
AlertDialog.Builder builder =
new AlertDialog.Builder(this)
.setTitle(R.string.select_vcard_title)
@@ -592,7 +650,7 @@
CharSequence[] items = new CharSequence[size];
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (int i = 0; i < size; i++) {
- VCardFile vcardFile = vcardFileList.get(i);
+ VCardFile vcardFile = mAllVCardFileList.get(i);
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
stringBuilder.append(vcardFile.getName());
stringBuilder.append('\n');
@@ -607,31 +665,150 @@
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
items[i] = stringBuilder;
}
- builder.setSingleChoiceItems(items, 0, listener);
- builder.show();
+ if (multipleSelect) {
+ builder.setMultiChoiceItems(items, (boolean[])null, listener);
+ } else {
+ builder.setSingleChoiceItems(items, 0, listener);
+ }
+ return builder.create();
}
- private void showReadingVCardDialog(DialogInterface.OnCancelListener listener) {
- String title = getString(R.string.reading_vcard_title);
- String message = getString(R.string.reading_vcard_message);
- mProgressDialog = new ProgressDialog(this);
- mProgressDialog.setTitle(title);
- mProgressDialog.setMessage(message);
- mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- mProgressDialog.setOnCancelListener(listener);
- mProgressDialog.show();
+ private Dialog getReadingVCardDialog() {
+ if (mProgressDialogForReadVCard == null) {
+ String title = getString(R.string.reading_vcard_title);
+ String message = getString(R.string.reading_vcard_message);
+ mProgressDialogForReadVCard = new ProgressDialog(this);
+ mProgressDialogForReadVCard.setTitle(title);
+ mProgressDialogForReadVCard.setMessage(message);
+ mProgressDialogForReadVCard.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ mProgressDialogForReadVCard.setOnCancelListener(mVCardReadThread);
+ mVCardReadThread.start();
+ }
+ return mProgressDialogForReadVCard;
}
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
- mLastNameComesBeforeFirstName = getResources().getBoolean(
- com.android.internal.R.bool.config_lastname_comes_before_firstname);
+ Intent intent = getIntent();
+ if (intent != null) {
+ final String accountName = intent.getStringExtra("account_name");
+ final String accountType = intent.getStringExtra("account_type");
+ if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
+ mAccount = new Account(accountName, accountType);
+ }
+ } else {
+ Log.e(LOG_TAG, "intent does not exist");
+ }
startImportVCardFromSdCard();
}
+ @Override
+ protected Dialog onCreateDialog(int resId) {
+ switch (resId) {
+ case R.id.dialog_searching_vcard: {
+ if (mProgressDialogForScanVCard == null) {
+ String title = getString(R.string.searching_vcard_title);
+ String message = getString(R.string.searching_vcard_message);
+ mProgressDialogForScanVCard =
+ ProgressDialog.show(this, title, message, true, false);
+ mProgressDialogForScanVCard.setOnCancelListener(mVCardScanThread);
+ mVCardScanThread.start();
+ }
+ return mProgressDialogForScanVCard;
+ }
+ case R.id.dialog_sdcard_not_found: {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(R.string.no_sdcard_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.no_sdcard_message)
+ .setOnCancelListener(mCancelListener)
+ .setPositiveButton(android.R.string.ok, mCancelListener);
+ return builder.create();
+ }
+ case R.id.dialog_vcard_not_found: {
+ String message = (getString(R.string.scanning_sdcard_failed_message,
+ getString(R.string.fail_reason_no_vcard_file)));
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(R.string.scanning_sdcard_failed_title)
+ .setMessage(message)
+ .setOnCancelListener(mCancelListener)
+ .setPositiveButton(android.R.string.ok, mCancelListener);
+ return builder.create();
+ }
+ case R.id.dialog_select_import_type: {
+ return getSelectImportTypeDialog();
+ }
+ case R.id.dialog_select_multiple_vcard: {
+ return getVCardFileSelectDialog(true);
+ }
+ case R.id.dialog_select_one_vcard: {
+ return getVCardFileSelectDialog(false);
+ }
+ case R.id.dialog_reading_vcard: {
+ return getReadingVCardDialog();
+ }
+ case R.id.dialog_io_exception: {
+ String message = (getString(R.string.scanning_sdcard_failed_message,
+ getString(R.string.fail_reason_io_error)));
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(R.string.scanning_sdcard_failed_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(message)
+ .setOnCancelListener(mCancelListener)
+ .setPositiveButton(android.R.string.ok, mCancelListener);
+ return builder.create();
+ }
+ case R.id.dialog_error_with_message: {
+ String message = mErrorMessage;
+ if (TextUtils.isEmpty(message)) {
+ Log.e(LOG_TAG, "Error message is null while it must not.");
+ message = getString(R.string.fail_reason_unknown);
+ }
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(getString(R.string.reading_vcard_failed_title))
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(message)
+ .setOnCancelListener(mCancelListener)
+ .setPositiveButton(android.R.string.ok, mCancelListener);
+ return builder.create();
+ }
+ }
+
+ return super.onCreateDialog(resId);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (mVCardReadThread != null) {
+ // The Activity is no longer visible. Stop the thread.
+ mVCardReadThread.cancel();
+ mVCardReadThread = null;
+ }
+
+ // ImportVCardActivity should not be persistent. In other words, if there's some
+ // event calling onStop(), this Activity should finish its work and give the main
+ // screen back to the caller Activity.
+ if (!isFinishing()) {
+ finish();
+ }
+ }
+
+ @Override
+ public void finalize() {
+ if (mVCardReadThread != null) {
+ // Not sure this procedure is really needed, but just in case...
+ Log.w(LOG_TAG, "VCardReadThread exists while this Activity is now being killed!");
+ mVCardReadThread.cancel();
+ mVCardReadThread = null;
+ }
+ }
+
+ /* public methods */
+
/**
* Tries to start importing VCard. If there's no SDCard available,
* an error dialog is shown. If there is, start scanning using another thread
@@ -641,21 +818,11 @@
public void startImportVCardFromSdCard() {
File file = new File("/sdcard");
if (!file.exists() || !file.isDirectory() || !file.canRead()) {
- new AlertDialog.Builder(this)
- .setTitle(R.string.no_sdcard_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(R.string.no_sdcard_message)
- .setOnCancelListener(mCancelListener)
- .setPositiveButton(android.R.string.ok, mCancelListener)
- .show();
+ showDialog(R.id.dialog_sdcard_not_found);
} else {
- String title = getString(R.string.searching_vcard_title);
- String message = getString(R.string.searching_vcard_message);
-
- mProgressDialog = ProgressDialog.show(this, title, message, true, false);
- VCardScanThread thread = new VCardScanThread(file);
- mProgressDialog.setOnCancelListener(thread);
- thread.start();
+ File sdcardDirectory = new File("/sdcard");
+ mVCardScanThread = new VCardScanThread(sdcardDirectory);
+ showDialog(R.id.dialog_searching_vcard);
}
}
}
diff --git a/src/com/android/contacts/PhoneDisambigDialog.java b/src/com/android/contacts/PhoneDisambigDialog.java
new file mode 100644
index 0000000..b727c77
--- /dev/null
+++ b/src/com/android/contacts/PhoneDisambigDialog.java
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.contacts.Collapser.Collapsible;
+
+import android.app.AlertDialog;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.database.Cursor;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.telephony.PhoneNumberUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.ListAdapter;
+
+/**
+ * Class used for displaying a dialog with a list of phone numbers of which
+ * one will be chosen to make a call or initiate an sms message.
+ */
+public class PhoneDisambigDialog implements DialogInterface.OnClickListener,
+ DialogInterface.OnDismissListener, CompoundButton.OnCheckedChangeListener{
+
+ private boolean mMakePrimary = false;
+ private Context mContext;
+ private AlertDialog mDialog;
+ private boolean mSendSms;
+ private Cursor mPhonesCursor;
+ private ListAdapter mPhonesAdapter;
+ private ArrayList<PhoneItem> mPhoneItemList;
+
+ public PhoneDisambigDialog(Context context, Cursor phonesCursor) {
+ this(context, phonesCursor, false /*make call*/);
+ }
+
+ public PhoneDisambigDialog(Context context, Cursor phonesCursor, boolean sendSms) {
+ mContext = context;
+ mSendSms = sendSms;
+ mPhonesCursor = phonesCursor;
+
+ mPhoneItemList = makePhoneItemsList(phonesCursor);
+ Collapser.collapseList(mPhoneItemList);
+
+ mPhonesAdapter = new PhonesAdapter(mContext, mPhoneItemList);
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ View setPrimaryView = inflater.
+ inflate(R.layout.set_primary_checkbox, null);
+ ((CheckBox) setPrimaryView.findViewById(R.id.setPrimary)).
+ setOnCheckedChangeListener(this);
+
+ // Need to show disambig dialogue.
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext).
+ setAdapter(mPhonesAdapter, this).
+ setTitle(sendSms ?
+ R.string.sms_disambig_title : R.string.call_disambig_title).
+ setView(setPrimaryView);
+
+ mDialog = dialogBuilder.create();
+ }
+
+ /**
+ * Show the dialog.
+ */
+ public void show() {
+ if (mPhoneItemList.size() == 1) {
+ // If there is only one after collapse, just select it, and close;
+ onClick(mDialog, 0);
+ return;
+ }
+ mDialog.show();
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (mPhoneItemList.size() > which && which >= 0) {
+ PhoneItem phoneItem = mPhoneItemList.get(which);
+ long id = phoneItem.id;
+ String phone = phoneItem.phoneNumber;
+
+ if (mMakePrimary) {
+ ContentValues values = new ContentValues(1);
+ values.put(Data.IS_SUPER_PRIMARY, 1);
+ mContext.getContentResolver().update(ContentUris.
+ withAppendedId(Data.CONTENT_URI, id), values, null, null);
+ }
+
+ if (mSendSms) {
+ ContactsUtils.initiateSms(mContext, phone);
+ } else {
+ ContactsUtils.initiateCall(mContext, phone);
+ }
+ } else {
+ dialog.dismiss();
+ }
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mMakePrimary = isChecked;
+ }
+
+ public void onDismiss(DialogInterface dialog) {
+ mPhonesCursor.close();
+ }
+
+ private static class PhonesAdapter extends ArrayAdapter<PhoneItem> {
+
+ public PhonesAdapter(Context context, List<PhoneItem> objects) {
+ super(context, android.R.layout.simple_dropdown_item_1line,
+ android.R.id.text1, objects);
+ }
+ }
+
+ private class PhoneItem implements Collapsible<PhoneItem> {
+
+ String phoneNumber;
+ long id;
+
+ public PhoneItem(String newPhoneNumber, long newId) {
+ phoneNumber = newPhoneNumber;
+ id = newId;
+ }
+
+ public boolean collapseWith(PhoneItem phoneItem) {
+ if (!shouldCollapseWith(phoneItem)) {
+ return false;
+ }
+ // Just keep the number and id we already have.
+ return true;
+ }
+
+ public boolean shouldCollapseWith(PhoneItem phoneItem) {
+ if (PhoneNumberUtils.compare(PhoneDisambigDialog.this.mContext,
+ phoneNumber, phoneItem.phoneNumber)) {
+ return true;
+ }
+ return false;
+ }
+
+ public String toString() {
+ return phoneNumber;
+ }
+ }
+
+ private ArrayList<PhoneItem> makePhoneItemsList(Cursor phonesCursor) {
+ ArrayList<PhoneItem> phoneList = new ArrayList<PhoneItem>();
+
+ phonesCursor.moveToPosition(-1);
+ while (phonesCursor.moveToNext()) {
+ long id = phonesCursor.getLong(phonesCursor.getColumnIndex(Data._ID));
+ String phone = phonesCursor.getString(phonesCursor.getColumnIndex(Phone.NUMBER));
+ phoneList.add(new PhoneItem(phone, id));
+ }
+
+ return phoneList;
+ }
+}
diff --git a/src/com/android/contacts/ProgressShower.java b/src/com/android/contacts/ProgressShower.java
new file mode 100644
index 0000000..c1a2493
--- /dev/null
+++ b/src/com/android/contacts/ProgressShower.java
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+package com.android.contacts;
+
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.os.Handler;
+import android.pim.vcard.ContactStruct;
+import android.pim.vcard.EntryHandler;
+import android.pim.vcard.VCardConfig;
+import android.util.Log;
+
+public class ProgressShower implements EntryHandler {
+ public static final String LOG_TAG = "vcard.ProgressShower";
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final ProgressDialog mProgressDialog;
+ private final String mProgressMessage;
+
+ private long mTime;
+
+ private class ShowProgressRunnable implements Runnable {
+ private ContactStruct mContact;
+
+ public ShowProgressRunnable(ContactStruct contact) {
+ mContact = contact;
+ }
+
+ public void run() {
+ mProgressDialog.setMessage( mProgressMessage + "\n" +
+ mContact.getDisplayName());
+ mProgressDialog.incrementProgressBy(1);
+ }
+ }
+
+ public ProgressShower(ProgressDialog progressDialog,
+ String progressMessage,
+ Context context,
+ Handler handler) {
+ mContext = context;
+ mHandler = handler;
+ mProgressDialog = progressDialog;
+ mProgressMessage = progressMessage;
+ }
+
+ public void onParsingStart() {
+ }
+
+ public void onEntryCreated(ContactStruct contactStruct) {
+ long start = System.currentTimeMillis();
+
+ if (!contactStruct.isIgnorable()) {
+ if (mProgressDialog != null && mProgressMessage != null) {
+ if (mHandler != null) {
+ mHandler.post(new ShowProgressRunnable(contactStruct));
+ } else {
+ mProgressDialog.setMessage(mContext.getString(R.string.progress_shower_message,
+ mProgressMessage,
+ contactStruct.getDisplayName()));
+ }
+ }
+ }
+
+ mTime += System.currentTimeMillis() - start;
+ }
+
+ public void onParsingEnd() {
+ if (VCardConfig.showPerformanceLog()) {
+ Log.d(LOG_TAG,
+ String.format("Time to progress a dialog: %d ms", mTime));
+ }
+ }
+}
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java
index 54e9a05..d892def 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/RecentCallsListActivity.java
@@ -38,8 +38,9 @@
import android.os.SystemClock;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.Contacts.Intents.Insert;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
@@ -100,11 +101,11 @@
/** The projection to use when querying the phones table */
static final String[] PHONES_PROJECTION = new String[] {
- Phones.PERSON_ID,
- Phones.DISPLAY_NAME,
- Phones.TYPE,
- Phones.LABEL,
- Phones.NUMBER
+ PhoneLookup._ID,
+ PhoneLookup.DISPLAY_NAME,
+ PhoneLookup.TYPE,
+ PhoneLookup.LABEL,
+ PhoneLookup.NUMBER
};
static final int PERSON_ID_COLUMN_INDEX = 0;
@@ -321,7 +322,7 @@
} else {
Cursor phonesCursor =
RecentCallsListActivity.this.getContentResolver().query(
- Uri.withAppendedPath(Phones.CONTENT_FILTER_URL,
+ Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(ciq.number)),
PHONES_PROJECTION, null, null, null);
if (phonesCursor != null) {
@@ -452,11 +453,15 @@
// Format the cached call_log phone number
formattedNumber = formatPhoneNumber(number);
}
- // Set the text lines
+ // Set the text lines and call icon.
+ // Assumes the call back feature is on most of the
+ // time. For private and unknown numbers: hide it.
+ views.callView.setVisibility(View.VISIBLE);
+
if (!TextUtils.isEmpty(name)) {
views.line1View.setText(name);
views.labelView.setVisibility(View.VISIBLE);
- CharSequence numberLabel = Phones.getDisplayLabel(context, ntype, label,
+ CharSequence numberLabel = Phone.getDisplayLabel(context, ntype, label,
mLabelArray);
views.numberView.setVisibility(View.VISIBLE);
views.numberView.setText(formattedNumber);
@@ -469,8 +474,10 @@
} else {
if (number.equals(CallerInfo.UNKNOWN_NUMBER)) {
number = getString(R.string.unknown);
+ views.callView.setVisibility(View.INVISIBLE);
} else if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
number = getString(R.string.private_num);
+ views.callView.setVisibility(View.INVISIBLE);
} else if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
number = getString(R.string.payphone);
} else if (number.equals(mVoiceMailNumber)) {
@@ -655,8 +662,14 @@
* <p>
* Because of the shared {@link #sEditable} builder, <b>this method is not
* thread safe</b>, and should only be called from the GUI thread.
+ * <p>
+ * If the given String object is null or empty, return an empty String.
*/
private String formatPhoneNumber(String number) {
+ if (TextUtils.isEmpty(number)) {
+ return "";
+ }
+
// Cache formatting type if not already present
if (sFormattingType == FORMATTING_TYPE_INVALID) {
sFormattingType = PhoneNumberUtils.getFormatTypeForLocale(Locale.getDefault());
@@ -743,7 +756,7 @@
if (contactInfoPresent) {
menu.add(0, 0, 0, R.string.menu_viewContact)
.setIntent(new Intent(Intent.ACTION_VIEW,
- ContentUris.withAppendedId(People.CONTENT_URI, info.personId)));
+ ContentUris.withAppendedId(Contacts.CONTENT_URI, info.personId)));
}
if (numberUri != null && !isVoicemail) {
@@ -755,7 +768,7 @@
}
if (!contactInfoPresent && numberUri != null && !isVoicemail) {
Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
- intent.setType(People.CONTENT_ITEM_TYPE);
+ intent.setType(Contacts.CONTENT_ITEM_TYPE);
intent.putExtra(Insert.PHONE, number);
menu.add(0, 0, 0, R.string.recentCalls_addToContact)
.setIntent(intent);
@@ -775,7 +788,7 @@
}
case MENU_ITEM_VIEW_CONTACTS: {
- Intent intent = new Intent(Intent.ACTION_VIEW, People.CONTENT_URI);
+ Intent intent = new Intent(Intent.ACTION_VIEW, Contacts.CONTENT_URI);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
return true;
@@ -868,7 +881,7 @@
try {
Cursor phonesCursor =
RecentCallsListActivity.this.getContentResolver().query(
- Uri.withAppendedPath(Phones.CONTENT_FILTER_URL,
+ Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
number),
PHONES_PROJECTION, null, null, null);
if (phonesCursor != null) {
diff --git a/src/com/android/contacts/ScrollingTabWidget.java b/src/com/android/contacts/ScrollingTabWidget.java
new file mode 100644
index 0000000..b45abe4
--- /dev/null
+++ b/src/com/android/contacts/ScrollingTabWidget.java
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.widget.HorizontalScrollView;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+/*
+ * Tab widget that can contain more tabs than can fit on screen at once and scroll over them.
+ */
+public class ScrollingTabWidget extends RelativeLayout
+ implements OnClickListener, ViewTreeObserver.OnGlobalFocusChangeListener,
+ OnFocusChangeListener {
+
+ private static final String TAG = "ScrollingTabWidget";
+
+ private OnTabSelectionChangedListener mSelectionChangedListener;
+ private int mSelectedTab = 0;
+ private ImageView mLeftArrowView;
+ private ImageView mRightArrowView;
+ private HorizontalScrollView mTabsScrollWrapper;
+ private TabStripView mTabsView;
+ private LayoutInflater mInflater;
+
+ // Keeps track of the left most visible tab.
+ private int mLeftMostVisibleTabIndex = 0;
+
+ public ScrollingTabWidget(Context context) {
+ this(context, null);
+ }
+
+ public ScrollingTabWidget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ScrollingTabWidget(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs);
+
+ mInflater = (LayoutInflater) mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ setFocusable(true);
+ setOnFocusChangeListener(this);
+ if (!hasFocus()) {
+ setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS);
+ }
+
+ mLeftArrowView = (ImageView) mInflater.inflate(R.layout.tab_left_arrow, this, false);
+ mLeftArrowView.setOnClickListener(this);
+ mRightArrowView = (ImageView) mInflater.inflate(R.layout.tab_right_arrow, this, false);
+ mRightArrowView.setOnClickListener(this);
+ mTabsScrollWrapper = (HorizontalScrollView) mInflater.inflate(
+ R.layout.tab_layout, this, false);
+ mTabsView = (TabStripView) mTabsScrollWrapper.findViewById(android.R.id.tabs);
+ View accountNameView = mInflater.inflate(R.layout.tab_account_name, this, false);
+
+ mLeftArrowView.setVisibility(View.INVISIBLE);
+ mRightArrowView.setVisibility(View.INVISIBLE);
+
+ addView(mTabsScrollWrapper);
+ addView(mLeftArrowView);
+ addView(mRightArrowView);
+ addView(accountNameView);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ final ViewTreeObserver treeObserver = getViewTreeObserver();
+ if (treeObserver != null) {
+ treeObserver.addOnGlobalFocusChangeListener(this);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ final ViewTreeObserver treeObserver = getViewTreeObserver();
+ if (treeObserver != null) {
+ treeObserver.removeOnGlobalFocusChangeListener(this);
+ }
+ }
+
+ protected void updateArrowVisibility() {
+ int scrollViewLeftEdge = mTabsScrollWrapper.getScrollX();
+ int tabsViewLeftEdge = mTabsView.getLeft();
+ int scrollViewRightEdge = scrollViewLeftEdge + mTabsScrollWrapper.getWidth();
+ int tabsViewRightEdge = mTabsView.getRight();
+
+ int rightArrowCurrentVisibility = mRightArrowView.getVisibility();
+ if (scrollViewRightEdge == tabsViewRightEdge
+ && rightArrowCurrentVisibility == View.VISIBLE) {
+ mRightArrowView.setVisibility(View.INVISIBLE);
+ } else if (scrollViewRightEdge < tabsViewRightEdge
+ && rightArrowCurrentVisibility != View.VISIBLE) {
+ mRightArrowView.setVisibility(View.VISIBLE);
+ }
+
+ int leftArrowCurrentVisibility = mLeftArrowView.getVisibility();
+ if (scrollViewLeftEdge == tabsViewLeftEdge
+ && leftArrowCurrentVisibility == View.VISIBLE) {
+ mLeftArrowView.setVisibility(View.INVISIBLE);
+ } else if (scrollViewLeftEdge > tabsViewLeftEdge
+ && leftArrowCurrentVisibility != View.VISIBLE) {
+ mLeftArrowView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Returns the tab indicator view at the given index.
+ *
+ * @param index the zero-based index of the tab indicator view to return
+ * @return the tab indicator view at the given index
+ */
+ public View getChildTabViewAt(int index) {
+ return mTabsView.getChildAt(index);
+ }
+
+ /**
+ * Returns the number of tab indicator views.
+ *
+ * @return the number of tab indicator views.
+ */
+ public int getTabCount() {
+ return mTabsView.getChildCount();
+ }
+
+ /**
+ * Returns the {@link ViewGroup} that actually contains the tabs. This is where the tab
+ * views should be attached to when being inflated.
+ */
+ public ViewGroup getTabParent() {
+ return mTabsView;
+ }
+
+ public void removeAllTabs() {
+ mTabsView.removeAllViews();
+ }
+
+ @Override
+ public void dispatchDraw(Canvas canvas) {
+ updateArrowVisibility();
+ super.dispatchDraw(canvas);
+ }
+
+ /**
+ * Sets the current tab.
+ * This method is used to bring a tab to the front of the Widget,
+ * and is used to post to the rest of the UI that a different tab
+ * has been brought to the foreground.
+ *
+ * Note, this is separate from the traditional "focus" that is
+ * employed from the view logic.
+ *
+ * For instance, if we have a list in a tabbed view, a user may be
+ * navigating up and down the list, moving the UI focus (orange
+ * highlighting) through the list items. The cursor movement does
+ * not effect the "selected" tab though, because what is being
+ * scrolled through is all on the same tab. The selected tab only
+ * changes when we navigate between tabs (moving from the list view
+ * to the next tabbed view, in this example).
+ *
+ * To move both the focus AND the selected tab at once, please use
+ * {@link #focusCurrentTab}. Normally, the view logic takes care of
+ * adjusting the focus, so unless you're circumventing the UI,
+ * you'll probably just focus your interest here.
+ *
+ * @param index The tab that you want to indicate as the selected
+ * tab (tab brought to the front of the widget)
+ *
+ * @see #focusCurrentTab
+ */
+ public void setCurrentTab(int index) {
+ if (index < 0 || index >= getTabCount()) {
+ return;
+ }
+
+ if (mSelectedTab < getTabCount()) {
+ mTabsView.setSelected(mSelectedTab, false);
+ }
+ mSelectedTab = index;
+ mTabsView.setSelected(mSelectedTab, true);
+ }
+
+ /**
+ * Return index of the currently selected tab.
+ */
+ public int getCurrentTab() {
+ return mSelectedTab;
+ }
+
+ /**
+ * Sets the current tab and focuses the UI on it.
+ * This method makes sure that the focused tab matches the selected
+ * tab, normally at {@link #setCurrentTab}. Normally this would not
+ * be an issue if we go through the UI, since the UI is responsible
+ * for calling TabWidget.onFocusChanged(), but in the case where we
+ * are selecting the tab programmatically, we'll need to make sure
+ * focus keeps up.
+ *
+ * @param index The tab that you want focused (highlighted in orange)
+ * and selected (tab brought to the front of the widget)
+ *
+ * @see #setCurrentTab
+ */
+ public void focusCurrentTab(int index) {
+ if (index < 0 || index >= getTabCount()) {
+ return;
+ }
+
+ setCurrentTab(index);
+ getChildTabViewAt(index).requestFocus();
+
+ }
+
+ /**
+ * Adds a tab to the list of tabs. The tab's indicator view is specified
+ * by a layout id. InflateException will be thrown if there is a problem
+ * inflating.
+ *
+ * @param layoutResId The layout id to be inflated to make the tab indicator.
+ */
+ public void addTab(int layoutResId) {
+ addTab(mInflater.inflate(layoutResId, mTabsView, false));
+ }
+
+ /**
+ * Adds a tab to the list of tabs. The tab's indicator view must be provided.
+ *
+ * @param child
+ */
+ public void addTab(View child) {
+ if (child == null) {
+ return;
+ }
+
+ if (child.getLayoutParams() == null) {
+ final LayoutParams lp = new LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ lp.setMargins(0, 0, 0, 0);
+ child.setLayoutParams(lp);
+ }
+
+ // Ensure you can navigate to the tab with the keyboard, and you can touch it
+ child.setFocusable(true);
+ child.setClickable(true);
+ child.setOnClickListener(new TabClickListener());
+ child.setOnFocusChangeListener(this);
+
+ mTabsView.addView(child);
+ }
+
+ /**
+ * Provides a way for ViewContactActivity and EditContactActivity to be notified that the
+ * user clicked on a tab indicator.
+ */
+ public void setTabSelectionListener(OnTabSelectionChangedListener listener) {
+ mSelectionChangedListener = listener;
+ }
+
+ public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+ if (isTab(oldFocus) && !isTab(newFocus)) {
+ onLoseFocus();
+ }
+ }
+
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (v == this && hasFocus) {
+ onObtainFocus();
+ return;
+ }
+
+ if (hasFocus) {
+ for (int i = 0; i < getTabCount(); i++) {
+ if (getChildTabViewAt(i) == v) {
+ setCurrentTab(i);
+ mSelectionChangedListener.onTabSelectionChanged(i, false);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Called when the {@link ScrollingTabWidget} gets focus. Here the
+ * widget decides which of it's tabs should have focus.
+ */
+ protected void onObtainFocus() {
+ // Setting this flag, allows the children of this View to obtain focus.
+ setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+ // Assign focus to the last selected tab.
+ focusCurrentTab(mSelectedTab);
+ mSelectionChangedListener.onTabSelectionChanged(mSelectedTab, false);
+ }
+
+ /**
+ * Called when the focus has left the {@link ScrollingTabWidget} or its
+ * descendants. At this time we want the children of this view to be marked
+ * as un-focusable, so that next time focus is moved to the widget, the widget
+ * gets control, and can assign focus where it wants.
+ */
+ protected void onLoseFocus() {
+ // Setting this flag will effectively make the tabs unfocusable. This will
+ // be toggled when the widget obtains focus again.
+ setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS);
+ }
+
+ public boolean isTab(View v) {
+ for (int i = 0; i < getTabCount(); i++) {
+ if (getChildTabViewAt(i) == v) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private class TabClickListener implements OnClickListener {
+ public void onClick(View v) {
+ for (int i = 0; i < getTabCount(); i++) {
+ if (getChildTabViewAt(i) == v) {
+ setCurrentTab(i);
+ mSelectionChangedListener.onTabSelectionChanged(i, true);
+ break;
+ }
+ }
+ }
+ }
+
+ public interface OnTabSelectionChangedListener {
+ /**
+ * Informs the tab widget host which tab was selected. It also indicates
+ * if the tab was clicked/pressed or just focused into.
+ *
+ * @param tabIndex index of the tab that was selected
+ * @param clicked whether the selection changed due to a touch/click
+ * or due to focus entering the tab through navigation. Pass true
+ * if it was due to a press/click and false otherwise.
+ */
+ void onTabSelectionChanged(int tabIndex, boolean clicked);
+ }
+
+ public void onClick(View v) {
+ updateLeftMostVisible();
+ if (v == mRightArrowView && (mLeftMostVisibleTabIndex + 1 < getTabCount())) {
+ tabScroll(true /* right */);
+ } else if (v == mLeftArrowView && mLeftMostVisibleTabIndex > 0) {
+ tabScroll(false /* left */);
+ }
+ }
+
+ /*
+ * Updates our record of the left most visible tab. We keep track of this explicitly
+ * on arrow clicks, but need to re-calibrate after focus navigation.
+ */
+ protected void updateLeftMostVisible() {
+ int viewableLeftEdge = mTabsScrollWrapper.getScrollX();
+
+ if (mLeftArrowView.getVisibility() == View.VISIBLE) {
+ viewableLeftEdge += mLeftArrowView.getWidth();
+ }
+
+ for (int i = 0; i < getTabCount(); i++) {
+ View tab = getChildTabViewAt(i);
+ int tabLeftEdge = tab.getLeft();
+ if (tabLeftEdge >= viewableLeftEdge) {
+ mLeftMostVisibleTabIndex = i;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Scrolls the tabs by exactly one tab width.
+ *
+ * @param directionRight if true, scroll to the right, if false, scroll to the left.
+ */
+ protected void tabScroll(boolean directionRight) {
+ int scrollWidth = 0;
+ View newLeftMostVisibleTab = null;
+ if (directionRight) {
+ newLeftMostVisibleTab = getChildTabViewAt(++mLeftMostVisibleTabIndex);
+ } else {
+ newLeftMostVisibleTab = getChildTabViewAt(--mLeftMostVisibleTabIndex);
+ }
+
+ scrollWidth = newLeftMostVisibleTab.getLeft() - mTabsScrollWrapper.getScrollX();
+ if (mLeftMostVisibleTabIndex > 0) {
+ scrollWidth -= mLeftArrowView.getWidth();
+ }
+ mTabsScrollWrapper.smoothScrollBy(scrollWidth, 0);
+ }
+
+}
diff --git a/src/com/android/contacts/ShowOrCreateActivity.java b/src/com/android/contacts/ShowOrCreateActivity.java
deleted file mode 100755
index 0732ffe..0000000
--- a/src/com/android/contacts/ShowOrCreateActivity.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.contacts;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.AsyncQueryHandler;
-import android.content.ComponentName;
-import android.content.ContentUris;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.Contacts;
-import android.provider.Contacts.ContactMethods;
-import android.provider.Contacts.ContactMethodsColumns;
-import android.provider.Contacts.Intents;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
-import android.util.Log;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Handle several edge cases around showing or possibly creating contacts in
- * connected with a specific E-mail address or phone number. Will search based
- * on incoming {@link Intent#getData()} as described by
- * {@link Intents#SHOW_OR_CREATE_CONTACT}.
- * <ul>
- * <li>If no matching contacts found, will prompt user with dialog to add to a
- * contact, then will use {@link Intent#ACTION_INSERT_OR_EDIT} to let create new
- * contact or edit new data into an existing one.
- * <li>If one matching contact found, directly show {@link Intent#ACTION_VIEW}
- * that specific contact.
- * <li>If more than one matching found, show list of matching contacts using
- * {@link Intent#ACTION_SEARCH}.
- * </ul>
- */
-public final class ShowOrCreateActivity extends Activity {
- static final String TAG = "ShowOrCreateActivity";
- static final boolean LOGD = false;
-
- static final String[] PHONES_PROJECTION = new String[] {
- Phones.PERSON_ID,
- };
-
- static final String[] PEOPLE_PROJECTION = new String[] {
- People._ID,
- };
-
- static final String SCHEME_MAILTO = "mailto";
- static final String SCHEME_TEL = "tel";
-
- static final int PERSON_ID_INDEX = 0;
-
- /**
- * Query clause to filter {@link ContactMethods#CONTENT_URI} to only search
- * {@link Contacts#KIND_EMAIL} or {@link Contacts#KIND_IM}.
- */
- static final String QUERY_KIND_EMAIL_OR_IM = ContactMethodsColumns.KIND +
- " IN (" + Contacts.KIND_EMAIL + "," + Contacts.KIND_IM + ")";
-
- static final int QUERY_TOKEN = 42;
-
- private QueryHandler mQueryHandler;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- // Create handler if doesn't exist, otherwise cancel any running
- if (mQueryHandler == null) {
- mQueryHandler = new QueryHandler(this);
- } else {
- mQueryHandler.cancelOperation(QUERY_TOKEN);
- }
-
- final Intent intent = getIntent();
- final Uri data = intent.getData();
-
- // Unpack scheme and target data from intent
- String scheme = null;
- String ssp = null;
- if (data != null) {
- scheme = data.getScheme();
- ssp = data.getSchemeSpecificPart();
- }
-
- // Build set of extras for possible use when creating contact
- Bundle createExtras = new Bundle();
- Bundle originalExtras = intent.getExtras();
- if (originalExtras != null) {
- createExtras.putAll(originalExtras);
- }
- mQueryHandler.setCreateExtras(createExtras);
-
- // Read possible extra with specific title
- String createDescrip = intent.getStringExtra(Intents.EXTRA_CREATE_DESCRIPTION);
- if (createDescrip == null) {
- createDescrip = ssp;
- }
- mQueryHandler.setCreateDescription(createDescrip);
-
- // Allow caller to bypass dialog prompt
- boolean createForce = intent.getBooleanExtra(Intents.EXTRA_FORCE_CREATE, false);
- mQueryHandler.setCreateForce(createForce);
-
- // Handle specific query request
- if (SCHEME_MAILTO.equals(scheme)) {
- createExtras.putString(Intents.Insert.EMAIL, ssp);
- Uri uri = Uri.withAppendedPath(People.WITH_EMAIL_OR_IM_FILTER_URI, Uri.encode(ssp));
- mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
- PEOPLE_PROJECTION, null, null, null);
- } else if (SCHEME_TEL.equals(scheme)) {
- createExtras.putString(Intents.Insert.PHONE, ssp);
- mQueryHandler.startQuery(QUERY_TOKEN, null,
- Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, ssp),
- PHONES_PROJECTION, null, null, null);
-
- } else {
- Log.w(TAG, "Invalid intent:" + getIntent());
- finish();
- }
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- if (mQueryHandler != null) {
- mQueryHandler.cancelOperation(QUERY_TOKEN);
- }
- }
-
- /**
- * Listener for {@link DialogInterface} that launches a given {@link Intent}
- * when clicked. When clicked, this also closes the parent using
- * {@link Activity#finish()}.
- */
- private static class IntentClickListener implements DialogInterface.OnClickListener {
- private Activity mParent;
- private Intent mIntent;
-
- /**
- * @param parent {@link Activity} to use for launching target.
- * @param intent Target {@link Intent} to launch when clicked.
- */
- public IntentClickListener(Activity parent, Intent intent) {
- mParent = parent;
- mIntent = intent;
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if (mIntent != null) {
- mParent.startActivity(mIntent);
- }
- mParent.finish();
- }
- }
-
- /**
- * Handle asynchronous query to find matching contacts. When query finishes,
- * will handle based on number of matching contacts found.
- */
- private static final class QueryHandler extends AsyncQueryHandler {
- private final WeakReference<Activity> mActivity;
- private Bundle mCreateExtras;
- private String mCreateDescrip;
- private boolean mCreateForce;
-
- public QueryHandler(Activity activity) {
- super(activity.getContentResolver());
- mActivity = new WeakReference<Activity>(activity);
- }
-
- public void setCreateExtras(Bundle createExtras) {
- mCreateExtras = createExtras;
- }
-
- public void setCreateDescription(String createDescrip) {
- mCreateDescrip = createDescrip;
- }
-
- public void setCreateForce(boolean createForce) {
- mCreateForce = createForce;
- }
-
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- Activity activity = mActivity.get();
- if (activity == null) {
- return;
- }
-
- // Count contacts found by query
- int count = 0;
- long personId = -1;
- if (cursor != null) {
- try {
- count = cursor.getCount();
- if (count == 1 && cursor.moveToFirst()) {
- // Try reading ID if only one contact returned
- personId = cursor.getLong(PERSON_ID_INDEX);
- }
- } finally {
- cursor.close();
- }
- }
-
- if (LOGD) Log.d(TAG, "onQueryComplete count=" + count);
-
- if (count == 1) {
- // If we only found one item, jump right to viewing it
- Intent viewIntent = new Intent(Intent.ACTION_VIEW,
- ContentUris.withAppendedId(People.CONTENT_URI, personId));
- activity.startActivity(viewIntent);
- activity.finish();
-
- } else if (count > 1) {
- // If more than one, show pick list
- Intent listIntent = new Intent(Intent.ACTION_SEARCH);
- listIntent.setComponent(new ComponentName(activity, ContactsListActivity.class));
- listIntent.putExtras(mCreateExtras);
- activity.startActivity(listIntent);
- activity.finish();
-
- } else {
- // No matching contacts found
- if (mCreateForce) {
- // Forced to create new contact
- Intent createIntent = new Intent(Intent.ACTION_INSERT, People.CONTENT_URI);
- createIntent.putExtras(mCreateExtras);
- createIntent.setType(People.CONTENT_TYPE);
-
- activity.startActivity(createIntent);
- activity.finish();
-
- } else {
- // Prompt user to insert or edit contact
- Intent createIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
- createIntent.putExtras(mCreateExtras);
- createIntent.setType(People.CONTENT_ITEM_TYPE);
-
- CharSequence message = activity.getResources().getString(
- R.string.add_contact_dlg_message_fmt, mCreateDescrip);
-
- new AlertDialog.Builder(activity)
- .setTitle(R.string.add_contact_dlg_title)
- .setMessage(message)
- .setPositiveButton(android.R.string.ok,
- new IntentClickListener(activity, createIntent))
- .setNegativeButton(android.R.string.cancel,
- new IntentClickListener(activity, null))
- .show();
- }
- }
- }
- }
-}
diff --git a/src/com/android/contacts/SpecialCharSequenceMgr.java b/src/com/android/contacts/SpecialCharSequenceMgr.java
index 999e141..644b66f 100644
--- a/src/com/android/contacts/SpecialCharSequenceMgr.java
+++ b/src/com/android/contacts/SpecialCharSequenceMgr.java
@@ -179,14 +179,14 @@
static boolean handleIMEIDisplay(Context context, String input, boolean useSystemWindow) {
if (input.equals(MMI_IMEI_DISPLAY)) {
- int networkType = ((TelephonyManager)context.getSystemService(
- Context.TELEPHONY_SERVICE)).getNetworkType();
- // check for GSM
- if(networkType == TelephonyManager.NETWORK_TYPE_GPRS ||
- networkType == TelephonyManager.NETWORK_TYPE_EDGE ||
- networkType == TelephonyManager.NETWORK_TYPE_UMTS ) {
+ int phoneType = ((TelephonyManager)context.getSystemService(
+ Context.TELEPHONY_SERVICE)).getPhoneType();
- showIMEIPanel(context, useSystemWindow);
+ if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
+ showIMEIPanel(context, useSystemWindow);
+ return true;
+ } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
+ showMEIDPanel(context, useSystemWindow);
return true;
}
}
@@ -207,6 +207,19 @@
alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PRIORITY_PHONE);
}
+ static void showMEIDPanel(Context context, boolean useSystemWindow) {
+ String meidStr = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE))
+ .getDeviceId();
+
+ AlertDialog alert = new AlertDialog.Builder(context)
+ .setTitle(R.string.meid)
+ .setMessage(meidStr)
+ .setPositiveButton(android.R.string.ok, null)
+ .setCancelable(false)
+ .show();
+ alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PRIORITY_PHONE);
+ }
+
/*******
* This code is used to handle SIM Contact queries
*******/
diff --git a/src/com/android/contacts/SplitAggregateView.java b/src/com/android/contacts/SplitAggregateView.java
new file mode 100644
index 0000000..ed78fd9
--- /dev/null
+++ b/src/com/android/contacts/SplitAggregateView.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts;
+
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.Sources;
+import com.google.common.util.text.TextUtil;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Contacts.Data;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * A list view for constituent contacts of an aggregate. Shows the contact name, source icon
+ * and additional data such as a nickname, email address or phone number, whichever
+ * is available.
+ */
+public class SplitAggregateView extends ListView {
+
+ private static final String TAG = "SplitAggregateView";
+
+ private interface SplitQuery {
+ String[] COLUMNS = new String[] {
+ Data.MIMETYPE, RawContacts.ACCOUNT_TYPE, Data.RAW_CONTACT_ID, Data.IS_PRIMARY,
+ StructuredName.DISPLAY_NAME, Nickname.NAME, Email.DATA, Phone.NUMBER
+ };
+
+ int MIMETYPE = 0;
+ int ACCOUNT_TYPE = 1;
+ int RAW_CONTACT_ID = 2;
+ int IS_PRIMARY = 3;
+ int DISPLAY_NAME = 4;
+ int NICKNAME = 5;
+ int EMAIL = 6;
+ int PHONE = 7;
+ }
+
+ private final Uri mAggregateUri;
+ private OnContactSelectedListener mListener;
+ private Sources mSources;
+
+ /**
+ * Listener interface that gets the contact ID of the user-selected contact.
+ */
+ public interface OnContactSelectedListener {
+ void onContactSelected(long rawContactId);
+ }
+
+ /**
+ * Constructor.
+ */
+ public SplitAggregateView(Context context, Uri aggregateUri) {
+ super(context);
+
+ mAggregateUri = aggregateUri;
+
+ mSources = Sources.getInstance(context);
+
+ final List<RawContactInfo> list = loadData();
+
+ setAdapter(new SplitAggregateAdapter(context, list));
+ setOnItemClickListener(new OnItemClickListener() {
+
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ mListener.onContactSelected(list.get(position).rawContactId);
+ }
+ });
+ }
+
+ /**
+ * Sets a contact selection listener.
+ */
+ public void setOnContactSelectedListener(OnContactSelectedListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Contact information loaded from the content provider.
+ */
+ private static class RawContactInfo implements Comparable<RawContactInfo> {
+ final long rawContactId;
+ String accountType;
+ String name;
+ String phone;
+ String email;
+ String nickname;
+
+ public RawContactInfo(long rawContactId) {
+ this.rawContactId = rawContactId;
+ }
+
+ public String getAdditionalData() {
+ if (nickname != null) {
+ return nickname;
+ }
+
+ if (email != null) {
+ return email;
+ }
+
+ if (phone != null) {
+ return phone;
+ }
+
+ return "";
+ }
+
+ public int compareTo(RawContactInfo another) {
+ String thisAccount = accountType != null ? accountType : "";
+ String thatAccount = another.accountType != null ? another.accountType : "";
+ return thisAccount.compareTo(thatAccount);
+ }
+ }
+
+ /**
+ * Loads data from the content provider, organizes it into {@link RawContactInfo} objects
+ * and returns a sorted list of {@link RawContactInfo}'s.
+ */
+ private List<RawContactInfo> loadData() {
+ HashMap<Long, RawContactInfo> rawContactInfos = new HashMap<Long, RawContactInfo>();
+ Uri dataUri = Uri.withAppendedPath(mAggregateUri, Data.CONTENT_DIRECTORY);
+ Cursor cursor = getContext().getContentResolver().query(dataUri,
+ SplitQuery.COLUMNS, null, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ long rawContactId = cursor.getLong(SplitQuery.RAW_CONTACT_ID);
+ RawContactInfo info = rawContactInfos.get(rawContactId);
+ if (info == null) {
+ info = new RawContactInfo(rawContactId);
+ rawContactInfos.put(rawContactId, info);
+ info.accountType = cursor.getString(SplitQuery.ACCOUNT_TYPE);
+ }
+
+ String mimetype = cursor.getString(SplitQuery.MIMETYPE);
+ if (StructuredName.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ loadStructuredName(cursor, info);
+ } else if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ loadPhoneNumber(cursor, info);
+ } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ loadEmail(cursor, info);
+ } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimetype)) {
+ loadNickname(cursor, info);
+ }
+ }
+ } finally {
+ cursor.close();
+ }
+
+ List<RawContactInfo> list = new ArrayList<RawContactInfo>(rawContactInfos.values());
+ Collections.sort(list);
+ return list;
+ }
+
+ private void loadStructuredName(Cursor cursor, RawContactInfo info) {
+ info.name = cursor.getString(SplitQuery.DISPLAY_NAME);
+ }
+
+ private void loadNickname(Cursor cursor, RawContactInfo info) {
+ if (info.nickname == null || cursor.getInt(SplitQuery.IS_PRIMARY) != 0) {
+ info.nickname = cursor.getString(SplitQuery.NICKNAME);
+ }
+ }
+
+ private void loadEmail(Cursor cursor, RawContactInfo info) {
+ if (info.email == null || cursor.getInt(SplitQuery.IS_PRIMARY) != 0) {
+ info.email = cursor.getString(SplitQuery.EMAIL);
+ }
+ }
+
+ private void loadPhoneNumber(Cursor cursor, RawContactInfo info) {
+ if (info.phone == null || cursor.getInt(SplitQuery.IS_PRIMARY) != 0) {
+ info.phone = cursor.getString(SplitQuery.PHONE);
+ }
+ }
+
+ private static class SplitAggregateItemCache {
+ TextView name;
+ TextView additionalData;
+ ImageView sourceIcon;
+ }
+
+ /**
+ * List adapter for the list of {@link RawContactInfo} objects.
+ */
+ private class SplitAggregateAdapter extends ArrayAdapter<RawContactInfo> {
+
+ private LayoutInflater mInflater;
+
+ public SplitAggregateAdapter(Context context, List<RawContactInfo> sources) {
+ super(context, 0, sources);
+ mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.split_aggregate_list_item, parent, false);
+ }
+
+ SplitAggregateItemCache cache = (SplitAggregateItemCache)convertView.getTag();
+ if (cache == null) {
+ cache = new SplitAggregateItemCache();
+ cache.name = (TextView)convertView.findViewById(R.id.name);
+ cache.additionalData = (TextView)convertView.findViewById(R.id.additionalData);
+ cache.sourceIcon = (ImageView)convertView.findViewById(R.id.sourceIcon);
+ convertView.setTag(cache);
+ }
+
+ final RawContactInfo info = getItem(position);
+ cache.name.setText(info.name);
+ cache.additionalData.setText(info.getAdditionalData());
+
+ Drawable icon = null;
+ ContactsSource source = mSources.getInflatedSource(info.accountType,
+ ContactsSource.LEVEL_SUMMARY);
+ if (source != null) {
+ icon = source.getDisplayIcon(getContext());
+ }
+ if (icon != null) {
+ cache.sourceIcon.setImageDrawable(icon);
+ } else {
+ cache.sourceIcon.setImageResource(R.drawable.unknown_source);
+ }
+ return convertView;
+ }
+ }
+}
diff --git a/src/com/android/contacts/TabStripView.java b/src/com/android/contacts/TabStripView.java
new file mode 100644
index 0000000..9b875d1
--- /dev/null
+++ b/src/com/android/contacts/TabStripView.java
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewParent;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+
+/** Extension of LinearLayout that takes care of drawing bottom strips over the tab children. */
+public class TabStripView extends LinearLayout {
+
+ private Drawable mBottomLeftStrip;
+ private Drawable mBottomRightStrip;
+ private int mSelectedTabIndex;
+
+ public TabStripView(Context context) {
+ this(context, null);
+ }
+
+ public TabStripView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;
+ mBottomLeftStrip = mContext.getResources().getDrawable(
+ R.drawable.tab_bottom);
+ mBottomRightStrip = mContext.getResources().getDrawable(
+ R.drawable.tab_bottom);
+ }
+
+ public void setSelected(int index, boolean selected) {
+ mSelectedTabIndex = index;
+ getChildAt(index).setSelected(selected);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ ViewParent parent = getParent();
+ if (parent instanceof HorizontalScrollView) {
+ setMinimumWidth(((HorizontalScrollView) getParent()).getMeasuredWidth());
+ }
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected int getChildDrawingOrder(int childCount, int i) {
+ // Always draw the selected tab last, so that drop shadows are drawn
+ // in the correct z-order.
+ if (i == childCount - 1) {
+ return mSelectedTabIndex;
+ } else if (i >= mSelectedTabIndex) {
+ return i + 1;
+ } else {
+ return i;
+ }
+ }
+
+ @Override
+ public void childDrawableStateChanged(View child) {
+ if (child == getChildAt(mSelectedTabIndex)) {
+ // To make sure that the bottom strip is redrawn
+ invalidate();
+ }
+ super.childDrawableStateChanged(child);
+ }
+
+ @Override
+ public void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+
+ View selectedChild = getChildAt(mSelectedTabIndex);
+
+ mBottomRightStrip.setState(selectedChild.getDrawableState());
+ mBottomLeftStrip.setState(selectedChild.getDrawableState());
+
+ Rect selBounds = new Rect(); // Bounds of the selected tab indicator
+ selBounds.left = selectedChild.getLeft() - getScrollX();
+ selBounds.right = selectedChild.getRight() - getScrollX();
+ final int myHeight = getHeight();
+ mBottomLeftStrip.setBounds(
+ Math.min(0, selBounds.left
+ - mBottomLeftStrip.getIntrinsicWidth()),
+ myHeight - mBottomLeftStrip.getIntrinsicHeight(),
+ selBounds.left,
+ myHeight);
+ mBottomRightStrip.setBounds(
+ selBounds.right,
+ myHeight - mBottomRightStrip.getIntrinsicHeight(),
+ Math.max(getWidth(),
+ selBounds.right + mBottomRightStrip.getIntrinsicWidth()),
+ myHeight);
+
+ mBottomLeftStrip.draw(canvas);
+ mBottomRightStrip.draw(canvas);
+ }
+
+}
diff --git a/src/com/android/contacts/TwelveKeyDialer.java b/src/com/android/contacts/TwelveKeyDialer.java
index 33f261e..2d8b4e6 100644
--- a/src/com/android/contacts/TwelveKeyDialer.java
+++ b/src/com/android/contacts/TwelveKeyDialer.java
@@ -34,6 +34,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Vibrator;
import android.provider.Contacts.Intents.Insert;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
@@ -44,6 +45,7 @@
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.Editable;
+import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.DialerKeyListener;
@@ -73,14 +75,18 @@
AdapterView.OnItemClickListener, TextWatcher {
private static final String TAG = "TwelveKeyDialer";
-
- private static final int STOP_TONE = 1;
/** The length of DTMF tones in milliseconds */
private static final int TONE_LENGTH_MS = 150;
-
+
/** The DTMF tone volume relative to other sounds in the stream */
- private static final int TONE_RELATIVE_VOLUME = 50;
+ private static final int TONE_RELATIVE_VOLUME = 80;
+
+ /** Stream type used to play the DTMF tones off call, and mapped to the volume control keys */
+ private static final int DIAL_TONE_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ /** Play the vibrate pattern only once. */
+ private static final int VIBRATE_NO_REPEAT = -1;
private EditText mDigits;
private View mDelete;
@@ -89,18 +95,44 @@
private Object mToneGeneratorLock = new Object();
private Drawable mDigitsBackground;
private Drawable mDigitsEmptyBackground;
- private Drawable mDeleteBackground;
- private Drawable mDeleteEmptyBackground;
- private View mDigitsAndBackspace;
private View mDialpad;
+ private View mVoicemailDialAndDeleteRow;
+ private View mVoicemailButton;
+ private View mDialButton;
private ListView mDialpadChooser;
private DialpadChooserAdapter mDialpadChooserAdapter;
+ //Member variables for dialpad options
+ private MenuItem m2SecPauseMenuItem;
+ private MenuItem mWaitMenuItem;
+ private static final int MENU_ADD_CONTACTS = 1;
+ private static final int MENU_2S_PAUSE = 2;
+ private static final int MENU_WAIT = 3;
// determines if we want to playback local DTMF tones.
private boolean mDTMFToneEnabled;
-
+
+ // Vibration (haptic feedback) for dialer key presses.
+ private Vibrator mVibrator;
+ private boolean mVibrateOn;
+ private long[] mVibratePattern;
+
+
/** Identifier for the "Add Call" intent extra. */
static final String ADD_CALL_MODE_KEY = "add_call_mode";
+
+ /**
+ * Identifier for intent extra for sending an empty Flash message for
+ * CDMA networks. This message is used by the network to simulate a
+ * press/depress of the "hookswitch" of a landline phone. Aka "empty flash".
+ *
+ * TODO: Using an intent extra to tell the phone to send this flash is a
+ * temporary measure. To be replaced with an ITelephony call in the future.
+ * TODO: Keep in sync with the string defined in OutgoingCallBroadcaster.java
+ * in Phone app until this is replaced with the ITelephony API.
+ */
+ static final String EXTRA_SEND_EMPTY_FLASH
+ = "com.android.phone.extra.SEND_EMPTY_FLASH";
+
/** Indicates if we are opening this dialer to add a call from the InCallScreen. */
private boolean mIsAddCallMode;
@@ -133,7 +165,7 @@
public void onTextChanged(CharSequence input, int start, int before, int changeCount) {
// Do nothing
- // DTMF Tones do not need to be played here any longer -
+ // DTMF Tones do not need to be played here any longer -
// the DTMF dialer handles that functionality now.
}
@@ -143,17 +175,15 @@
mDigits.getText().clear();
}
- // Set the proper background for the dial input area
- if (mDigits.length() != 0) {
- mDelete.setBackgroundDrawable(mDeleteBackground);
+ final boolean notEmpty = mDigits.length() != 0;
+ if (notEmpty) {
mDigits.setBackgroundDrawable(mDigitsBackground);
- mDigits.setCompoundDrawablesWithIntrinsicBounds(
- getResources().getDrawable(R.drawable.ic_dial_number), null, null, null);
} else {
- mDelete.setBackgroundDrawable(mDeleteEmptyBackground);
+ mDigits.setCursorVisible(false);
mDigits.setBackgroundDrawable(mDigitsEmptyBackground);
- mDigits.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
}
+
+ updateDialAndDeleteButtonStateEnabledAttr();
}
@Override
@@ -163,21 +193,16 @@
// Set the content view
setContentView(getContentViewResource());
- // Load up the resources for the text field and delete button
+ // Load up the resources for the text field.
Resources r = getResources();
mDigitsBackground = r.getDrawable(R.drawable.btn_dial_textfield_active);
- //mDigitsBackground.setDither(true);
mDigitsEmptyBackground = r.getDrawable(R.drawable.btn_dial_textfield);
- //mDigitsEmptyBackground.setDither(true);
- mDeleteBackground = r.getDrawable(R.drawable.btn_dial_delete_active);
- //mDeleteBackground.setDither(true);
- mDeleteEmptyBackground = r.getDrawable(R.drawable.btn_dial_delete);
- //mDeleteEmptyBackground.setDither(true);
mDigits = (EditText) findViewById(R.id.digits);
mDigits.setKeyListener(DialerKeyListener.getInstance());
mDigits.setOnClickListener(this);
mDigits.setOnKeyListener(this);
+
maybeAddNumberFormatting();
// Check for the presence of the keypad
@@ -186,13 +211,35 @@
setupKeypad();
}
- view = findViewById(R.id.backspace);
+ mVoicemailDialAndDeleteRow = findViewById(R.id.voicemailAndDialAndDelete);
+
+ initVoicemailButton();
+
+ // Check whether we should show the onscreen "Dial" button.
+ mDialButton = mVoicemailDialAndDeleteRow.findViewById(R.id.dialButton);
+
+ if (r.getBoolean(R.bool.config_show_onscreen_dial_button)) {
+ mDialButton.setOnClickListener(this);
+ } else {
+ mDialButton.setVisibility(View.GONE); // It's VISIBLE by default
+ mDialButton = null;
+ }
+
+ view = mVoicemailDialAndDeleteRow.findViewById(R.id.deleteButton);
view.setOnClickListener(this);
view.setOnLongClickListener(this);
mDelete = view;
- mDigitsAndBackspace = (View) findViewById(R.id.digitsAndBackspace);
- mDialpad = (View) findViewById(R.id.dialpad); // This is null in landscape mode
+ mDialpad = findViewById(R.id.dialpad); // This is null in landscape mode.
+
+ // In landscape we put the keyboard in phone mode.
+ // In portrait we prevent the soft keyboard to show since the
+ // dialpad acts as one already.
+ if (null == mDialpad) {
+ mDigits.setInputType(android.text.InputType.TYPE_CLASS_PHONE);
+ } else {
+ mDigits.setInputType(android.text.InputType.TYPE_NULL);
+ }
// Set up the "dialpad chooser" UI; see showDialpadChooser().
mDialpadChooser = (ListView) findViewById(R.id.dialpadChooser);
@@ -202,44 +249,23 @@
super.onRestoreInstanceState(icicle);
}
- // If the mToneGenerator creation fails, just continue without it. It is
- // a local audio signal, and is not as important as the dtmf tone itself.
- synchronized (mToneGeneratorLock) {
- if (mToneGenerator == null) {
- try {
- mToneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL,
- TONE_RELATIVE_VOLUME);
- } catch (RuntimeException e) {
- Log.w(TAG, "Exception caught while creating local tone generator: " + e);
- mToneGenerator = null;
- }
- }
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- synchronized(mToneGeneratorLock) {
- if (mToneGenerator != null) {
- mToneStopper.removeMessages(STOP_TONE);
- mToneGenerator.release();
- mToneGenerator = null;
- }
- }
+ // TODO: We might eventually need to make mVibrateOn come from a
+ // user preference rather than a per-platform resource, in which
+ // case we would need to update it in onResume() rather than here.
+ initVibrationPattern(r);
}
@Override
protected void onRestoreInstanceState(Bundle icicle) {
// Do nothing, state is restored in onCreate() if needed
}
-
+
protected void maybeAddNumberFormatting() {
mDigits.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
}
-
+
/**
- * Overridden by subclasses to control the resource used by the content view.
+ * Overridden by subclasses to control the resource used by the content view.
*/
protected int getContentViewResource() {
return R.layout.twelve_key_dialer;
@@ -333,7 +359,7 @@
setIntent(newIntent);
resolveIntent();
}
-
+
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
@@ -344,7 +370,7 @@
// will always happen after onRestoreSavedInstanceState().
mDigits.addTextChangedListener(this);
}
-
+
private void setupKeypad() {
// Setup the listeners for the buttons
View view = findViewById(R.id.one);
@@ -371,25 +397,28 @@
@Override
protected void onResume() {
super.onResume();
-
+
// retrieve the DTMF tone play back setting.
mDTMFToneEnabled = Settings.System.getInt(getContentResolver(),
Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
- // if the mToneGenerator creation fails, just continue without it. It is
+ // if the mToneGenerator creation fails, just continue without it. It is
// a local audio signal, and is not as important as the dtmf tone itself.
synchronized(mToneGeneratorLock) {
if (mToneGenerator == null) {
try {
- mToneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL,
- TONE_RELATIVE_VOLUME);
+ // we want the user to be able to control the volume of the dial tones
+ // outside of a call, so we use the stream type that is also mapped to the
+ // volume control keys for this activity
+ mToneGenerator = new ToneGenerator(DIAL_TONE_STREAM_TYPE, TONE_RELATIVE_VOLUME);
+ setVolumeControlStream(DIAL_TONE_STREAM_TYPE);
} catch (RuntimeException e) {
Log.w(TAG, "Exception caught while creating local tone generator: " + e);
mToneGenerator = null;
}
}
}
-
+
Activity parent = getParent();
// See if we were invoked with a DIAL intent. If we were, fill in the appropriate
// digits in the dialer field.
@@ -425,6 +454,8 @@
// be visible if the phone is idle!
showDialpadChooser(false);
}
+
+ updateDialAndDeleteButtonStateEnabledAttr();
}
@Override
@@ -436,7 +467,7 @@
// have a window token yet in onCreate / onNewIntent
InputMethodManager inputMethodManager = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
- inputMethodManager.hideSoftInputFromWindow(mDigits.getWindowToken(), 0);
+ inputMethodManager.hideSoftInputFromWindow(mDigits.getWindowToken(), 0);
}
}
@@ -450,7 +481,6 @@
synchronized(mToneGeneratorLock) {
if (mToneGenerator != null) {
- mToneStopper.removeMessages(STOP_TONE);
mToneGenerator.release();
mToneGenerator = null;
}
@@ -459,9 +489,12 @@
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- mAddToContactMenuItem = menu.add(0, 0, 0, R.string.recentCalls_addToContact)
+ mAddToContactMenuItem = menu.add(0, MENU_ADD_CONTACTS, 0, R.string.recentCalls_addToContact)
.setIcon(android.R.drawable.ic_menu_add);
-
+ m2SecPauseMenuItem = menu.add(0, MENU_2S_PAUSE, 0, R.string.add_2sec_pause)
+ .setIcon(R.drawable.ic_menu_2sec_pause);
+ mWaitMenuItem = menu.add(0, MENU_WAIT, 0, R.string.add_wait)
+ .setIcon(R.drawable.ic_menu_wait);
return true;
}
@@ -475,6 +508,8 @@
CharSequence digits = mDigits.getText();
if (digits == null || !TextUtils.isGraphic(digits)) {
mAddToContactMenuItem.setVisible(false);
+ m2SecPauseMenuItem.setVisible(false);
+ mWaitMenuItem.setVisible(false);
} else {
// Put the current digits string into an intent
Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
@@ -482,6 +517,41 @@
intent.setType(People.CONTENT_ITEM_TYPE);
mAddToContactMenuItem.setIntent(intent);
mAddToContactMenuItem.setVisible(true);
+
+ // Check out whether to show Pause & Wait option menu items
+ int selectionStart;
+ int selectionEnd;
+ String strDigits = digits.toString();
+
+ selectionStart = mDigits.getSelectionStart();
+ selectionEnd = mDigits.getSelectionEnd();
+
+ if (selectionStart != -1) {
+ if (selectionStart > selectionEnd) {
+ // swap it as we want start to be less then end
+ int tmp = selectionStart;
+ selectionStart = selectionEnd;
+ selectionEnd = tmp;
+ }
+
+ if (selectionStart != 0) {
+ // Pause can be visible if cursor is not in the begining
+ m2SecPauseMenuItem.setVisible(true);
+
+ // For Wait to be visible set of condition to meet
+ mWaitMenuItem.setVisible(showWait(selectionStart,
+ selectionEnd, strDigits));
+ } else {
+ // cursor in the beginning both pause and wait to be invisible
+ m2SecPauseMenuItem.setVisible(false);
+ mWaitMenuItem.setVisible(false);
+ }
+ } else {
+ // cursor is not selected so assume new digit is added to the end
+ int strLength = strDigits.length();
+ mWaitMenuItem.setVisible(showWait(strLength,
+ strLength, strDigits));
+ }
}
return true;
}
@@ -503,7 +573,7 @@
return true;
}
case KeyEvent.KEYCODE_1: {
- long timeDiff = SystemClock.uptimeMillis() - event.getDownTime();
+ long timeDiff = SystemClock.uptimeMillis() - event.getDownTime();
if (timeDiff >= ViewConfiguration.getLongPressTimeout()) {
// Long press detected, call voice mail
callVoicemail();
@@ -518,7 +588,13 @@
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_CALL: {
- if (mIsAddCallMode && (TextUtils.isEmpty(mDigits.getText().toString()))) {
+ if (phoneIsCdma()) {
+ // If we're CDMA, regardless of where we are adding a call from (either
+ // InCallScreen or Dialtacts), the user may need to send an empty
+ // flash command to the network. So let's call placeCall() regardless
+ // and placeCall will handle this functionality for us.
+ placeCall();
+ } else if (mIsAddCallMode && (TextUtils.isEmpty(mDigits.getText().toString()))) {
// if we are adding a call from the InCallScreen and the phone
// number entered is empty, we just close the dialer to expose
// the InCallScreen under it.
@@ -532,8 +608,9 @@
}
return super.onKeyUp(keyCode, event);
}
-
+
private void keyPressed(int keyCode) {
+ vibrate();
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
mDigits.onKeyDown(keyCode, event);
}
@@ -612,14 +689,26 @@
keyPressed(KeyEvent.KEYCODE_STAR);
return;
}
- case R.id.backspace: {
+ case R.id.deleteButton: {
keyPressed(KeyEvent.KEYCODE_DEL);
return;
}
- case R.id.digits: {
+ case R.id.dialButton: {
+ vibrate(); // Vibrate here too, just like we do for the regular keys
placeCall();
return;
}
+ case R.id.voicemailButton: {
+ callVoicemail();
+ vibrate();
+ return;
+ }
+ case R.id.digits: {
+ if (mDigits.length() != 0) {
+ mDigits.setCursorVisible(true);
+ }
+ return;
+ }
}
}
@@ -627,8 +716,12 @@
final Editable digits = mDigits.getText();
int id = view.getId();
switch (id) {
- case R.id.backspace: {
+ case R.id.deleteButton: {
digits.clear();
+ // TODO: The framework forgets to clear the pressed
+ // status of disabled button. Until this is fixed,
+ // clear manually the pressed status. b/2133127
+ mDelete.setPressed(false);
return true;
}
case R.id.one: {
@@ -657,35 +750,34 @@
void placeCall() {
final String number = mDigits.getText().toString();
- if (number == null || !TextUtils.isGraphic(number)) {
- // There is no number entered.
- playTone(ToneGenerator.TONE_PROP_NACK);
- return;
- }
+ boolean sendEmptyFlash = false;
Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
Uri.fromParts("tel", number, null));
+ if (number == null || !TextUtils.isGraphic(number)) {
+ // There is no number entered.
+ if (phoneIsCdma() && phoneIsOffhook()) {
+ // We only want to send this empty flash extra if we're CDMA and the
+ // phone is offhook (don't want to send if ringing or dialing)
+ intent.putExtra(EXTRA_SEND_EMPTY_FLASH, true);
+ sendEmptyFlash = true;
+ } else {
+ playTone(ToneGenerator.TONE_PROP_NACK);
+ return;
+ }
+ }
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
mDigits.getText().clear();
- finish();
+ // Don't finish TwelveKeyDialer yet if we're sending a blank flash for CDMA. CDMA
+ // networks use Flash messages when special processing needs to be done, mainly for
+ // 3-way or call waiting scenarios. Presumably, here we're in a special 3-way scenario
+ // where the network needs a blank flash before being able to add the new participant.
+ // (This is not the case with all 3-way calls, just certain CDMA infrastructures.)
+ if (!sendEmptyFlash) {
+ finish();
+ }
}
- Handler mToneStopper = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case STOP_TONE:
- synchronized(mToneGeneratorLock) {
- if (mToneGenerator == null) {
- Log.w(TAG, "mToneStopper: mToneGenerator == null");
- } else {
- mToneGenerator.stopTone();
- }
- }
- break;
- }
- }
- };
/**
* Plays the specified tone for TONE_LENGTH_MS milliseconds.
@@ -719,13 +811,9 @@
Log.w(TAG, "playTone: mToneGenerator == null, tone: "+tone);
return;
}
-
- // Remove pending STOP_TONE messages
- mToneStopper.removeMessages(STOP_TONE);
-
+
// Start the new tone (will stop any playing tone)
- mToneGenerator.startTone(tone);
- mToneStopper.sendEmptyMessageDelayed(STOP_TONE, TONE_LENGTH_MS);
+ mToneGenerator.startTone(tone, TONE_LENGTH_MS);
}
}
@@ -748,8 +836,9 @@
private void showDialpadChooser(boolean enabled) {
if (enabled) {
// Log.i(TAG, "Showing dialpad chooser!");
- mDigitsAndBackspace.setVisibility(View.GONE);
+ mDigits.setVisibility(View.GONE);
if (mDialpad != null) mDialpad.setVisibility(View.GONE);
+ mVoicemailDialAndDeleteRow.setVisibility(View.GONE);
mDialpadChooser.setVisibility(View.VISIBLE);
// Instantiate the DialpadChooserAdapter and hook it up to the
@@ -760,8 +849,9 @@
}
} else {
// Log.i(TAG, "Displaying normal Dialer UI.");
- mDigitsAndBackspace.setVisibility(View.VISIBLE);
+ mDigits.setVisibility(View.VISIBLE);
if (mDialpad != null) mDialpad.setVisibility(View.VISIBLE);
+ mVoicemailDialAndDeleteRow.setVisibility(View.VISIBLE);
mDialpadChooser.setVisibility(View.GONE);
}
}
@@ -941,4 +1031,190 @@
}
return phoneInUse;
}
+
+ /**
+ * @return true if the phone is a CDMA phone type
+ */
+ private boolean phoneIsCdma() {
+ boolean isCdma = false;
+ try {
+ ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
+ if (phone != null) {
+ isCdma = (phone.getActivePhoneType() == TelephonyManager.PHONE_TYPE_CDMA);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "phone.getActivePhoneType() failed", e);
+ }
+ return isCdma;
+ }
+
+ /**
+ * @return true if the phone state is OFFHOOK
+ */
+ private boolean phoneIsOffhook() {
+ boolean phoneOffhook = false;
+ try {
+ ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
+ if (phone != null) phoneOffhook = phone.isOffhook();
+ } catch (RemoteException e) {
+ Log.w(TAG, "phone.isOffhook() failed", e);
+ }
+ return phoneOffhook;
+ }
+
+ /**
+ * Triggers haptic feedback (if enabled) for dialer key presses.
+ */
+ private synchronized void vibrate() {
+ if (!mVibrateOn) {
+ return;
+ }
+ if (mVibrator == null) {
+ mVibrator = new Vibrator();
+ }
+ mVibrator.vibrate(mVibratePattern, VIBRATE_NO_REPEAT);
+ }
+
+ /**
+ * Returns true whenever any one of the options from the menu is selected.
+ * Code changes to support dialpad options
+ */
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_2S_PAUSE:
+ updateDialString(",");
+ return true;
+ case MENU_WAIT:
+ updateDialString(";");
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Updates the dial string (mDigits) after inserting a Pause character (,)
+ * or Wait character (;).
+ */
+ private void updateDialString(String newDigits) {
+ int selectionStart;
+ int selectionEnd;
+
+ // SpannableStringBuilder editable_text = new SpannableStringBuilder(mDigits.getText());
+ int anchor = mDigits.getSelectionStart();
+ int point = mDigits.getSelectionEnd();
+
+ selectionStart = Math.min(anchor, point);
+ selectionEnd = Math.max(anchor, point);
+
+ Editable digits = mDigits.getText();
+ if (selectionStart != -1 ) {
+ if (selectionStart == selectionEnd) {
+ // then there is no selection. So insert the pause at this
+ // position and update the mDigits.
+ digits.replace(selectionStart, selectionStart, newDigits);
+ } else {
+ digits.replace(selectionStart, selectionEnd, newDigits);
+ // Unselect: back to a regular cursor, just pass the character inserted.
+ mDigits.setSelection(selectionStart + 1);
+ }
+ } else {
+ int len = mDigits.length();
+ digits.replace(len, len, newDigits);
+ }
+ }
+
+ /**
+ * Update the enabledness of the "Dial" and "Backspace" buttons if applicable.
+ */
+ private void updateDialAndDeleteButtonStateEnabledAttr() {
+ final boolean notEmpty = mDigits.length() != 0;
+
+ // If we're already on a CDMA call, then we want to enable the Call button
+ if (phoneIsCdma() && phoneIsOffhook()) {
+ if (mDialButton != null) {
+ mDialButton.setEnabled(true);
+ }
+ } else {
+ if (mDialButton != null) {
+ mDialButton.setEnabled(notEmpty);
+ }
+ }
+ mDelete.setEnabled(notEmpty);
+ }
+
+
+ /**
+ * Check if voicemail is enabled/accessible.
+ */
+ private void initVoicemailButton() {
+ boolean hasVoicemail = false;
+ try {
+ hasVoicemail = TelephonyManager.getDefault().getVoiceMailNumber() != null;
+ } catch (SecurityException se) {
+ // Possibly no READ_PHONE_STATE privilege.
+ }
+
+ mVoicemailButton = mVoicemailDialAndDeleteRow.findViewById(R.id.voicemailButton);
+ if (hasVoicemail) {
+ mVoicemailButton.setOnClickListener(this);
+ } else {
+ mVoicemailButton.setEnabled(false);
+ }
+ }
+
+ /**
+ * Initialize the vibration parameters.
+ * @param r The Resources with the vibration parameters.
+ */
+ private void initVibrationPattern(Resources r) {
+ int[] pattern = null;
+ try {
+ mVibrateOn = r.getBoolean(R.bool.config_enable_dialer_key_vibration);
+ pattern = r.getIntArray(com.android.internal.R.array.config_virtualKeyVibePattern);
+ if (null == pattern) {
+ Log.e(TAG, "Vibrate pattern is null.");
+ mVibrateOn = false;
+ }
+ } catch (Resources.NotFoundException nfe) {
+ Log.e(TAG, "Vibrate control bool or pattern missing.", nfe);
+ mVibrateOn = false;
+ }
+
+ if (!mVibrateOn) {
+ return;
+ }
+
+ // int[] to long[] conversion.
+ mVibratePattern = new long[pattern.length];
+ for (int i = 0; i < pattern.length; i++) {
+ mVibratePattern[i] = pattern[i];
+ }
+ }
+
+ /**
+ * This function return true if Wait menu item can be shown
+ * otherwise returns false. Assumes the passed string is non-empty
+ * and the 0th index check is not required.
+ */
+ private boolean showWait(int start, int end, String digits) {
+ if (start == end) {
+ // visible false in this case
+ if (start > digits.length()) return false;
+
+ // preceding char is ';', so visible should be false
+ if (digits.charAt(start-1) == ';') return false;
+
+ // next char is ';', so visible should be false
+ if ((digits.length() > start) && (digits.charAt(start) == ';')) return false;
+ } else {
+ // visible false in this case
+ if (start > digits.length() || end > digits.length()) return false;
+
+ // In this case we need to just check for ';' preceding to start
+ // or next to end
+ if (digits.charAt(start-1) == ';') return false;
+ }
+ return true;
+ }
}
diff --git a/src/com/android/contacts/TypePrecedence.java b/src/com/android/contacts/TypePrecedence.java
new file mode 100644
index 0000000..62520a0
--- /dev/null
+++ b/src/com/android/contacts/TypePrecedence.java
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.util.Constants;
+
+import android.accounts.Account;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+
+/**
+ * This class contains utility functions for determining the precedence of
+ * different types associated with contact data items.
+ *
+ * @deprecated use {@link EntityModifier#getTypePrecedence} instead, since this
+ * list isn't {@link Account} based.
+ */
+@Deprecated
+public final class TypePrecedence {
+
+ /* This utility class has cannot be instantiated.*/
+ private TypePrecedence() {}
+
+ //TODO These may need to be tweaked.
+ private static final int[] TYPE_PRECEDENCE_PHONES = {
+ Phone.TYPE_CUSTOM,
+ Phone.TYPE_MOBILE,
+ Phone.TYPE_HOME,
+ Phone.TYPE_WORK,
+ Phone.TYPE_OTHER,
+ Phone.TYPE_FAX_HOME,
+ Phone.TYPE_FAX_WORK,
+ Phone.TYPE_PAGER};
+
+ private static final int[] TYPE_PRECEDENCE_EMAIL = {
+ Email.TYPE_CUSTOM,
+ Email.TYPE_HOME,
+ Email.TYPE_WORK,
+ Email.TYPE_OTHER};
+
+ private static final int[] TYPE_PRECEDENCE_POSTAL = {
+ StructuredPostal.TYPE_CUSTOM,
+ StructuredPostal.TYPE_HOME,
+ StructuredPostal.TYPE_WORK,
+ StructuredPostal.TYPE_OTHER};
+
+ private static final int[] TYPE_PRECEDENCE_IM = {
+ Im.TYPE_CUSTOM,
+ Im.TYPE_HOME,
+ Im.TYPE_WORK,
+ Im.TYPE_OTHER};
+
+ private static final int[] TYPE_PRECEDENCE_ORG = {
+ Organization.TYPE_CUSTOM,
+ Organization.TYPE_WORK,
+ Organization.TYPE_OTHER};
+
+ /**
+ * Returns the precedence (1 being the highest) of a type in the context of it's mimetype.
+ *
+ * @param mimetype The mimetype of the data with which the type is associated.
+ * @param type The integer type as defined in {@Link ContactsContract#CommonDataKinds}.
+ * @return The integer precedence, where 1 is the highest.
+ */
+ @Deprecated
+ public static int getTypePrecedence(String mimetype, int type) {
+ int[] typePrecedence = getTypePrecedenceList(mimetype);
+ if (typePrecedence == null) {
+ return -1;
+ }
+
+ for (int i = 0; i < typePrecedence.length; i++) {
+ if (typePrecedence[i] == type) {
+ return i;
+ }
+ }
+ return typePrecedence.length;
+ }
+
+ @Deprecated
+ private static int[] getTypePrecedenceList(String mimetype) {
+ if (mimetype.equals(Phone.CONTENT_ITEM_TYPE)) {
+ return TYPE_PRECEDENCE_PHONES;
+ } else if (mimetype.equals(Constants.MIME_SMS_ADDRESS)) {
+ return TYPE_PRECEDENCE_PHONES;
+ } else if (mimetype.equals(Email.CONTENT_ITEM_TYPE)) {
+ return TYPE_PRECEDENCE_EMAIL;
+ } else if (mimetype.equals(StructuredPostal.CONTENT_ITEM_TYPE)) {
+ return TYPE_PRECEDENCE_POSTAL;
+ } else if (mimetype.equals(Im.CONTENT_ITEM_TYPE)) {
+ return TYPE_PRECEDENCE_IM;
+ } else if (mimetype.equals(Organization.CONTENT_ITEM_TYPE)) {
+ return TYPE_PRECEDENCE_ORG;
+ } else {
+ return null;
+ }
+ }
+
+
+}
diff --git a/src/com/android/contacts/VCardExporter.java b/src/com/android/contacts/VCardExporter.java
deleted file mode 100644
index 2b3c4eb..0000000
--- a/src/com/android/contacts/VCardExporter.java
+++ /dev/null
@@ -1,1674 +0,0 @@
-/*
- * 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.
- */
-package com.android.contacts;
-
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteException;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.provider.Contacts;
-import android.provider.Contacts.People;
-import android.syncml.pim.PropertyNode;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-public class VCardExporter {
- private static final String LOG_TAG = "VCardExporter";
-
- // If true, VCardExporter is able to emits files longer than 8.3 format.
- private static final boolean ALLOW_LONG_FILE_NAME = false;
- private final String mTargetDirectory;
- private final String mFileNamePrefix;
- private final String mFileNameSuffix;
- private final int mFileIndexMinimum;
- private final int mFileIndexMaximum;
- private final String mFileNameExtension;
- private final String mVCardType;
- private final Set<String> mExtensionsToConsider;
-
- private Context mParentContext;
- private Handler mParentHandler;
- private ProgressDialog mProgressDialog;
-
- private class ErrorMessageDisplayRunnable implements Runnable {
- private String mReason;
- public ErrorMessageDisplayRunnable(String reason) {
- mReason = reason;
- }
-
- public void run() {
- new AlertDialog.Builder(mParentContext)
- .setTitle(getString(R.string.exporting_contact_failed_title))
- .setMessage(getString(R.string.exporting_contact_failed_message, mReason))
- .setPositiveButton(android.R.string.ok, null)
- .show();
- }
- }
-
- private class ConfirmListener implements DialogInterface.OnClickListener {
- private String mFileName;
-
- public ConfirmListener(String fileName) {
- mFileName = fileName;
- }
-
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- startExport(mFileName);
- } else if (which == DialogInterface.BUTTON_NEGATIVE) {
- }
- }
- }
-
- private class ActualExportThread extends Thread
- implements DialogInterface.OnCancelListener {
- private PowerManager.WakeLock mWakeLock;
- private String mFileName;
- private boolean mCanceled = false;
-
- public ActualExportThread(String fileName) {
- mFileName = fileName;
- PowerManager powerManager = (PowerManager)mParentContext.getSystemService(
- Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(
- PowerManager.SCREEN_DIM_WAKE_LOCK |
- PowerManager.ON_AFTER_RELEASE, LOG_TAG);
- }
-
- @Override
- public void run() {
- mWakeLock.acquire();
- VCardExporterImpl exporterImpl = null;
- try {
- OutputStream outputStream = null;
- try {
- outputStream = new FileOutputStream(mFileName);
- } catch (FileNotFoundException e) {
- String reason = getString(R.string.fail_reason_could_not_open_file,
- mFileName, e.getMessage());
- mParentHandler.post(new ErrorMessageDisplayRunnable(reason));
- return;
- }
-
- TelephonyManager telephonyManager =
- (TelephonyManager)mParentContext.getSystemService(
- Context.TELEPHONY_SERVICE);
-
- exporterImpl = new VCardExporterImpl(mParentContext.getContentResolver(),
- outputStream, mVCardType);
-
- if (!exporterImpl.init()) {
- String reason = getString(R.string.fail_reason_could_not_initialize_exporter,
- exporterImpl.getErrorReason());
- mParentHandler.post(new ErrorMessageDisplayRunnable(reason));
- return;
- }
-
- int size = exporterImpl.getCount();
-
- mProgressDialog.setProgressNumberFormat(
- getString(R.string.exporting_contact_list_progress));
- mProgressDialog.setMax(size);
- mProgressDialog.setProgress(0);
-
- while (!exporterImpl.isAfterLast()) {
- if (mCanceled) {
- return;
- }
- if (!exporterImpl.exportOneContactData()) {
- Log.e(LOG_TAG, "Failed to read a contact.");
- String reason = getString(R.string.fail_reason_error_occurred_during_export,
- exporterImpl.getErrorReason());
- mParentHandler.post(new ErrorMessageDisplayRunnable(reason));
- return;
- }
- mProgressDialog.incrementProgressBy(1);
- }
- } finally {
- if (exporterImpl != null) {
- exporterImpl.terminate();
- }
- mWakeLock.release();
- mProgressDialog.dismiss();
- }
- }
-
- @Override
- public void finalize() {
- if (mWakeLock != null && mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- }
-
- public void onCancel(DialogInterface dialog) {
- mCanceled = true;
- }
- }
-
- /**
- * @param parentContext must not be null
- * @param parentHandler must not be null
- */
- public VCardExporter(Context parentContext, Handler parentHandler) {
- mParentContext = parentContext;
- mParentHandler = parentHandler;
- mTargetDirectory = getString(R.string.config_export_dir);
- mFileNamePrefix = getString(R.string.config_export_file_prefix);
- mFileNameSuffix = getString(R.string.config_export_file_suffix);
- mFileNameExtension = getString(R.string.config_export_file_extension);
- mVCardType = getString(R.string.config_export_vcard_type);
-
- mExtensionsToConsider = new HashSet<String>();
- mExtensionsToConsider.add(mFileNameExtension);
-
- final String additionalExtensions =
- getString(R.string.config_export_extensions_to_consider);
- if (!TextUtils.isEmpty(additionalExtensions)) {
- for (String extension : additionalExtensions.split(",")) {
- String trimed = extension.trim();
- if (trimed.length() > 0) {
- mExtensionsToConsider.add(trimed);
- }
- }
- }
-
- Resources resources = parentContext.getResources();
- mFileIndexMinimum = resources.getInteger(R.integer.config_export_file_min_index);
- mFileIndexMaximum = resources.getInteger(R.integer.config_export_file_max_index);
- }
-
- /**
- * Tries to start exporting VCard. If there's no SDCard available,
- * an error dialog is shown.
- */
- public void startExportVCardToSdCard() {
- File targetDirectory = new File(mTargetDirectory);
-
- if (!(targetDirectory.exists() &&
- targetDirectory.isDirectory() &&
- targetDirectory.canRead()) &&
- !targetDirectory.mkdirs()) {
- new AlertDialog.Builder(mParentContext)
- .setTitle(R.string.no_sdcard_title)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setMessage(R.string.no_sdcard_message)
- .setPositiveButton(android.R.string.ok, null)
- .show();
- } else {
- String fileName = getAppropriateFileName(mTargetDirectory);
- if (TextUtils.isEmpty(fileName)) {
- return;
- }
-
- new AlertDialog.Builder(mParentContext)
- .setTitle(R.string.confirm_export_title)
- .setMessage(getString(R.string.confirm_export_message, fileName))
- .setPositiveButton(android.R.string.ok, new ConfirmListener(fileName))
- .setNegativeButton(android.R.string.cancel, null)
- .show();
- }
- }
-
- /**
- * Tries to get an appropriate filename. Returns null if it fails.
- */
- private String getAppropriateFileName(final String destDirectory) {
- int fileNumberStringLength = 0;
- {
- // Calling Math.Log10() is costly.
- int tmp;
- for (fileNumberStringLength = 0, tmp = mFileIndexMaximum; tmp > 0;
- fileNumberStringLength++, tmp /= 10) {
- }
- }
- String bodyFormat = "%s%0" + fileNumberStringLength + "d%s";
-
- if (!ALLOW_LONG_FILE_NAME) {
- String possibleBody = String.format(bodyFormat,mFileNamePrefix, 1, mFileNameSuffix);
- if (possibleBody.length() > 8 || mFileNameExtension.length() > 3) {
- Log.e(LOG_TAG, "This code does not allow any long file name.");
- displayErrorMessage(getString(R.string.fail_reason_too_long_filename,
- String.format("%s.%s", possibleBody, mFileNameExtension)));
- return null;
- }
- }
-
- // Note that this logic assumes that the target directory is case insensitive.
- // As of 2009-07-16, it is true since the external storage is only sdcard, and
- // it is formated as FAT/VFAT.
- // TODO: fix this.
- for (int i = mFileIndexMinimum; i <= mFileIndexMaximum; i++) {
- boolean numberIsAvailable = true;
- // SD Association's specification seems to require this feature, though we cannot
- // have the specification since it is proprietary...
- String body = null;
- for (String possibleExtension : mExtensionsToConsider) {
- body = String.format(bodyFormat, mFileNamePrefix, i, mFileNameSuffix);
- File file = new File(String.format("%s/%s.%s",
- destDirectory, body, possibleExtension));
- if (file.exists()) {
- numberIsAvailable = false;
- break;
- }
- }
- if (numberIsAvailable) {
- return String.format("%s/%s.%s", destDirectory, body, mFileNameExtension);
- }
- }
- displayErrorMessage(getString(R.string.fail_reason_too_many_vcard));
- return null;
- }
-
- private void startExport(String fileName) {
- ActualExportThread thread = new ActualExportThread(fileName);
- displayReadingVCardDialog(thread, fileName);
- thread.start();
- }
-
- private void displayReadingVCardDialog(DialogInterface.OnCancelListener listener,
- String fileName) {
- String title = getString(R.string.exporting_contact_list_title);
- String message = getString(R.string.exporting_contact_list_message, fileName);
- mProgressDialog = new ProgressDialog(mParentContext);
- mProgressDialog.setTitle(title);
- mProgressDialog.setMessage(message);
- mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- mProgressDialog.setOnCancelListener(listener);
- mProgressDialog.show();
- }
-
- private void displayErrorMessage(String failureReason) {
- new AlertDialog.Builder(mParentContext)
- .setTitle(R.string.exporting_contact_failed_title)
- .setMessage(getString(R.string.exporting_contact_failed_message,
- failureReason))
- .setPositiveButton(android.R.string.ok, null)
- .show();
- }
-
- private String getString(int resId, Object... formatArgs) {
- return mParentContext.getString(resId, formatArgs);
- }
-
- private String getString(int resId) {
- return mParentContext.getString(resId);
- }
-}
-
-// TODO: This class should be splitted into two parts; exporter part and composer part.
-class VCardExporterImpl {
- private static final String LOG_TAG = "VCardExporterImpl";
-
- /* Type of exporting VCard. */
- // General VCard. Use UTF-8 and do not care vendor specific things.
- public static int VCARD_TYPE_GENERIC = 0;
- // VCard format used in DoCoMo. Shift_Jis is used as charset.
- public static int VCARD_TYPE_DOCOMO = 1;
- public static final String VCARD_TYPE_STRING_DOCOMO = "docomo";
-
- private static final String VCARD_PROPERTY_ADR = "ADR";
- private static final String VCARD_PROPERTY_BEGIN = "BEGIN";
- private static final String VCARD_PROPERTY_EMAIL = "EMAIL";
- private static final String VCARD_PROPERTY_END = "END";
- private static final String VCARD_PROPERTY_NAME = "N";
- private static final String VCARD_PROPERTY_NOTE = "NOTE";
- private static final String VCARD_PROPERTY_ORG = "ORG";
- private static final String VCARD_PROPERTY_SOUND = "SOUND";
- private static final String VCARD_PROPERTY_TEL = "TEL";
- private static final String VCARD_PROPERTY_TITLE = "TITLE";
- private static final String VCARD_PROPERTY_PHOTO = "PHOTO";
- private static final String VCARD_PROPERTY_VERSION = "VERSION";
- private static final String VCARD_PROPERTY_BDAY = "BDAY";
- private static final String VCARD_PROPERTY_URL = "URL";
-
- // Properties for DoCoMo vCard.
- private static final String VCARD_PROPERTY_X_CLASS = "X-CLASS";
- private static final String VCARD_PROPERTY_X_REDUCTION = "X-REDUCTION";
- private static final String VCARD_PROPERTY_X_NO = "X-NO";
- private static final String VCARD_PROPERTY_X_DCM_HMN_MODE = "X-DCM-HMN-MODE";
-
- private static final String VCARD_DATA_VCARD = "VCARD";
- private static final String VCARD_DATA_VERSION_V21 = "2.1";
- private static final String VCARD_DATA_PUBLIC = "PUBLIC";
-
- private static final String VCARD_ATTR_SEPARATOR = ";";
- private static final String VCARD_COL_SEPARATOR = "\r\n";
- private static final String VCARD_DATA_SEPARATOR = ":";
- private static final String VCARD_ITEM_SEPARATOR = ";";
- private static final String VCARD_WS = " ";
-
- private static final String VCARD_ATTR_VOICE = "VOICE";
- private static final String VCARD_ATTR_CELL = "CELL";
- private static final String VCARD_ATTR_WORK = "WORK";
- private static final String VCARD_ATTR_HOME = "HOME";
- private static final String VCARD_ATTR_FAX = "FAX";
- private static final String VCARD_ATTR_INTERNET = "INTERNET";
- private static final String VCARD_ATTR_ENCODING_QP = "ENCODING=QUOTED-PRINTABLE";
- private static final String VCARD_ATTR_ENCODING_BASE64_V21 = "ENCODING=BASE64";
- // This is just a reminder: in VCard 3.0, do not use the string "BASE64"
- @SuppressWarnings("unused")
- private static final String VCARD_ATTR_ENCODING_BASE64_V30 = "ENCODING=b";
-
- // DoCoMo specific attribute.Used with "SOUND" property.
- private static final String VCARD_ATTR_X_IRMC_N = "X-IRMC-N";
-
- private static final String SHIFT_JIS = "SHIFT_JIS";
-
- private Cursor mCursor;
- private int mIdColumn;
- private int mNameColumn;
- private int mNotesColumn;
- private int mPhoneticNameColumn;
- private ContentResolver mContentResolver;
-
- private int mVCardType;
- private String mCharsetString;
- private static String mVCardAttributeCharset;
- private OutputStream mOutputStream; // mWriter will close this.
- private Writer mWriter;
- private boolean mTerminateIsCalled;
-
- private String mErrorReason = "No error";
-
- /**
- * @param resolver
- * @param outputStream close() must not be called outside.
- * @param vcardType
- */
- public VCardExporterImpl(ContentResolver resolver, OutputStream outputStream, int vcardType) {
- mContentResolver = resolver;
- mOutputStream = outputStream;
-
- mVCardType = vcardType;
- if (vcardType == VCARD_TYPE_DOCOMO) {
- mCharsetString = CharsetUtils.charsetForVendor(SHIFT_JIS, "docomo").name();
- mVCardAttributeCharset = "CHARSET=" + SHIFT_JIS;
- } else {
- mCharsetString = "UTF-8";
- mVCardAttributeCharset = "CHARSET=UTF-8";
- }
- }
-
- public VCardExporterImpl(ContentResolver resolver, OutputStream outputStream, String vcardType) {
- this(resolver, outputStream,
- (vcardType.equalsIgnoreCase(VCARD_TYPE_STRING_DOCOMO) ?
- VCARD_TYPE_DOCOMO : VCARD_TYPE_GENERIC));
- }
-
- /**
- * @return Returns true when initialization is successful and all the other methods are
- * available. Returns false otherwise.
- */
- public boolean init() {
- try {
- mWriter = new BufferedWriter(
- new OutputStreamWriter(mOutputStream, mCharsetString));
- } catch (UnsupportedEncodingException e1) {
- Log.e(LOG_TAG, "Unsupported charset: " + mCharsetString);
- mErrorReason = "Encoding is not supported (usually this does not happen!): " +
- mCharsetString;
- return false;
- }
-
- final String[] projection = new String[] {
- People._ID,
- People.NAME,
- People.NOTES,
- People.PHONETIC_NAME,
- };
-
- mCursor = mContentResolver.query(People.CONTENT_URI, projection, null, null, null);
- if (mCursor == null || !mCursor.moveToFirst()) {
- if (mCursor != null) {
- try {
- mCursor.close();
- } catch (SQLiteException e) {
- }
- mCursor = null;
- }
- mErrorReason = "Getting database information failed.";
- return false;
- }
-
- mIdColumn = mCursor.getColumnIndex(People._ID);
- mNameColumn = mCursor.getColumnIndex(People.NAME);
- mNotesColumn = mCursor.getColumnIndex(People.NOTES);
- mPhoneticNameColumn = mCursor.getColumnIndex(People.PHONETIC_NAME);
-
- if (mVCardType == VCARD_TYPE_DOCOMO) {
- try {
- mWriter.write(convertContactToVCard(new ContactData()));
- } catch (IOException e) {
- Log.e(LOG_TAG, "IOException occurred during exportOneContactData: " +
- e.getMessage());
- mErrorReason = "IOException occurred: " + e.getMessage();
- }
- }
-
- return true;
- }
-
- @Override
- public void finalize() {
- if (!mTerminateIsCalled) {
- terminate();
- }
- }
-
- public void terminate() {
- if (mWriter != null) {
- try {
- // Flush and sync the data so that a user is able to pull the SDCard just after the
- // export.
- mWriter.flush();
- if (mOutputStream != null && mOutputStream instanceof FileOutputStream) {
- try {
- ((FileOutputStream)mOutputStream).getFD().sync();
- } catch (IOException e) {
- }
- }
- mWriter.close();
- } catch (IOException e) {
- }
- }
- if (mCursor != null) {
- try {
- mCursor.close();
- } catch (SQLiteException e) {
- }
- mCursor = null;
- }
- }
-
- public int getCount() {
- if (mCursor == null) {
- return 0;
- }
- return mCursor.getCount();
- }
-
- public boolean isAfterLast() {
- if (mCursor == null) {
- return false;
- }
- return mCursor.isAfterLast();
- }
-
- public boolean exportOneContactData() {
- if (mCursor == null || mCursor.isAfterLast()) {
- mErrorReason = "Not initialized or database has some problem.";
- return false;
- }
- String name = null;
- try {
- ContactData contactData = new ContactData();
- int personId = mCursor.getInt(mIdColumn);
- name = contactData.mName = mCursor.getString(mNameColumn);
- contactData.mNote = mCursor.getString(mNotesColumn);
- contactData.mPhoneticName = mCursor.getString(mPhoneticNameColumn);
-
- readAllPhones(contactData, personId);
- readAllAddresses(contactData, personId);
- readAllOrgs(contactData, personId);
- readAllPhotos(contactData, personId);
- readAllExtensions(contactData, personId);
-
- mCursor.moveToNext();
-
- String vcardString = convertContactToVCard(contactData);
- try {
- mWriter.write(vcardString);
- } catch (IOException e) {
- Log.e(LOG_TAG, "IOException occurred during exportOneContactData: " +
- e.getMessage());
- mErrorReason = "IOException occurred: " + e.getMessage();
- return false;
- }
- } catch (OutOfMemoryError error) {
- // Maybe some data (e.g. photo) is too big to have in memory. But it should be rare.
- Log.e(LOG_TAG, "OutOfMemoryError occured. Ignore the entry: " + name);
- System.gc();
- }
-
- return true;
- }
-
- /**
- * @return Return the error reason if possible.
- */
- public String getErrorReason() {
- return mErrorReason;
- }
-
- private void readAllPhones(ContactData contact, int personId) {
- final String[] projection = new String[] {
- Contacts.Phones.TYPE,
- Contacts.Phones.LABEL,
- Contacts.Phones.NUMBER,
- Contacts.Phones.LABEL,
- };
- String selection = String.format("%s=%d", Contacts.Phones.PERSON_ID, personId);
- Cursor cursor = null;
- try {
- cursor = mContentResolver.query(Contacts.Phones.CONTENT_URI,
- projection, selection, null, null);
- if ((cursor != null) && (cursor.moveToFirst())) {
- int typeColumn = cursor.getColumnIndex(Contacts.Phones.TYPE);
- int labelColumn = cursor.getColumnIndex(Contacts.Phones.LABEL);
- int numberColumn = cursor.getColumnIndex(Contacts.Phones.NUMBER);
- do {
- TelData telData = new TelData(cursor.getInt(typeColumn),
- cursor.getString(labelColumn), cursor.getString(numberColumn));
- contact.mTel.add(telData);
- } while (cursor.moveToNext());
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- private void readAllPhotos(ContactData contact, int personId) {
- final String[] projection = new String[] {
- Contacts.Photos.DATA,
- };
- String selection = String.format("%s=%d", Contacts.Photos.PERSON_ID, personId);
- Cursor cursor = null;
- try {
- cursor = mContentResolver.query(Contacts.Photos.CONTENT_URI,
- projection, selection, null, null);
- if ((cursor != null) && (cursor.moveToFirst())) {
- int dataColumn = cursor.getColumnIndex(Contacts.Photos.DATA);
-
- byte[] data;
- do {
- data = cursor.getBlob(dataColumn);
- // Use some heuristics for guessing the format of the image.
- if (data != null && data.length > 0) {
- if (data.length >= 3 &&
- data[0] == 'G' && data[1] == 'I' && data[2] == 'F') {
- contact.mPhotoType = "GIF";
- } else if (data.length >= 4 &&
- data[0] == (byte)0x89 && data[1] == 'P' && data[2] == 'N' &&
- data[3] == 'G') {
- // Note: vCard 2.1 officially does not support PNG, but we may have it
- // and using X- word like "X-PNG" may not let importers know it is
- // PNG. So we use the String "PNG" as is...
- contact.mPhotoType = "PNG";
- } else if (data.length >= 2 &&
- data[0] == (byte)0xff && data[1] == (byte)0xd8) {
- contact.mPhotoType = "JPEG";
- } else {
- // TODO: vCard specification requires the other formats like TIFF...
- Log.d(LOG_TAG, "Unknown photo type. Ignore.");
- continue;
- }
- }
- String photoData = encodeBase64(data);
- if (photoData.length() > 0) {
- contact.mPhoto = photoData;
- }
- } while (cursor.moveToNext());
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- private void readAllAddresses(ContactData contact, int personId) {
- final String[] projection = new String[] {
- Contacts.ContactMethods.TYPE,
- Contacts.ContactMethods.LABEL,
- Contacts.ContactMethods.DATA,
- Contacts.ContactMethods.KIND,
- };
- String selection = String.format("%s=%d AND %s IN (1,2)",
- Contacts.ContactMethods.PERSON_ID, personId, Contacts.ContactMethods.KIND);
- Cursor cursor = null;
- try {
- cursor = mContentResolver.query(Contacts.ContactMethods.CONTENT_URI,
- projection, selection, null, null);
- if ((cursor != null) && (cursor.moveToFirst())) {
- int typeColumn = cursor.getColumnIndex(Contacts.ContactMethods.TYPE);
- int labelColumn = cursor.getColumnIndex(Contacts.ContactMethods.LABEL);
- int dataColumn = cursor.getColumnIndex(Contacts.ContactMethods.DATA);
- int kindColumn = cursor.getColumnIndex(Contacts.ContactMethods.KIND);
- do {
- int kind = cursor.getInt(kindColumn);
-
- switch(kind) {
- case Contacts.KIND_EMAIL:
- EmailData emailData = new EmailData(cursor.getInt(typeColumn),
- cursor.getString(labelColumn), cursor.getString(dataColumn));
- contact.mEmail.add(emailData);
- break;
- case Contacts.KIND_POSTAL:
- AddressData addr = new AddressData(cursor.getInt(typeColumn),
- cursor.getString(labelColumn), cursor.getString(dataColumn));
- contact.mAddr.add(addr);
- break;
- default:
- break;
- }
- } while (cursor.moveToNext());
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- private void readAllOrgs(ContactData contactData, int personId) {
- final String[] projection = new String[] {
- Contacts.Organizations.COMPANY,
- Contacts.Organizations.TITLE,
- };
- String selection = String.format("%s=%d", Contacts.ContactMethods.PERSON_ID, personId);
- Cursor cursor = null;
- try {
- cursor = mContentResolver.query(Contacts.Organizations.CONTENT_URI,
- projection, selection, null, null);
- if ((cursor != null) && (cursor.moveToFirst())) {
- int companyColumn = cursor.getColumnIndex(Contacts.Organizations.COMPANY);
- int titleColumn = cursor.getColumnIndex(Contacts.Organizations.TITLE);
- do {
- contactData.mOrg = cursor.getString(companyColumn);
- contactData.mTitle = cursor.getString(titleColumn);
- } while (cursor.moveToNext());
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- private void readAllExtensions(ContactData contactData, int personId) {
- final String[] projection = new String[] {
- Contacts.Extensions.NAME,
- Contacts.Extensions.VALUE,
- };
- String selection = String.format("%s=%d", Contacts.Extensions.PERSON_ID, personId);
- Cursor cursor = null;
- try {
- cursor = mContentResolver.query(Contacts.Extensions.CONTENT_URI,
- projection, selection, null, null);
- if ((cursor != null) && (cursor.moveToFirst())) {
- int nameColumn = cursor.getColumnIndex(Contacts.Extensions.NAME);
- int valueColumn = cursor.getColumnIndex(Contacts.Extensions.VALUE);
- do {
- contactData.mExtensions.put(
- cursor.getString(nameColumn),
- cursor.getString(valueColumn));
- } while (cursor.moveToNext());
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- private String toHalfWidthString(String orgString) {
- StringBuilder builder = new StringBuilder();
- int length = orgString.length();
- for (int i = 0; i < length; i++) {
- // All Japanese character is able to be expressed by char.
- // Do not need to use String#codepPointAt().
- char ch = orgString.charAt(i);
- CharSequence halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch);
- if (halfWidthText != null) {
- builder.append(halfWidthText);
- } else {
- builder.append(ch);
- }
- }
- return builder.toString();
- }
-
- private String encodeSomeCharacters(String str) {
- char[] strArray = str.toCharArray();
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < strArray.length; i++) {
- char ch = strArray[i];
- switch (ch) {
- case ';':
- builder.append('\\');
- builder.append(';');
- break;
- case '\r':
- case '\n':
- // ignore
- break;
- case '\\':
- case '<':
- case '>':
- if (mVCardType == VCARD_TYPE_DOCOMO) {
- builder.append('\\');
- builder.append(ch);
- }
- break;
- default:
- builder.append(ch);
- break;
- }
- }
- return builder.toString();
- }
-
- private String convertContactToVCard(ContactData contactData) {
- // Some DoCoMo mobile devices cannot parse a VCard data which does not have empty field.
- final boolean isDoCoMo = (mVCardType == VCARD_TYPE_DOCOMO);
- StringBuilder builder = new StringBuilder();
- appendVCardLine(builder, VCARD_PROPERTY_BEGIN, VCARD_DATA_VCARD);
- appendVCardLine(builder, VCARD_PROPERTY_VERSION, VCARD_DATA_VERSION_V21);
-
- if (!TextUtils.isEmpty(contactData.mName)) {
- builder.append(VCARD_PROPERTY_NAME);
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(mVCardAttributeCharset);
- builder.append(VCARD_DATA_SEPARATOR);
- builder.append(encodeSomeCharacters(contactData.mName));
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_COL_SEPARATOR);
- } else if (isDoCoMo) {
- appendVCardLine(builder, VCARD_PROPERTY_NAME, "");
- }
-
- if (!TextUtils.isEmpty(contactData.mPhoneticName)) {
- // Note: There is no appropriate property for expressing phonetic name in VCard 2.1,
- // while there is in VCard 3.0 (SORT-STRING).
- // We choose to use DoCoMo's way since it is supported by Japanese mobile phones.
- builder.append(VCARD_PROPERTY_SOUND);
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(VCARD_ATTR_X_IRMC_N);
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(mVCardAttributeCharset);
- builder.append(VCARD_DATA_SEPARATOR);
- // TODO: Not only DoCoMo but also other Japanese mobile careers requires this.
- String phoneticName =
- (isDoCoMo ? toHalfWidthString(contactData.mPhoneticName) :
- contactData.mPhoneticName);
- builder.append(encodeSomeCharacters(phoneticName));
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_COL_SEPARATOR);
- } else if (isDoCoMo) {
- // VCARD_ITEM_SEPARATOR should be inserted for DoCoMo devices.
- builder.append(VCARD_PROPERTY_SOUND);
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(VCARD_ATTR_X_IRMC_N);
- builder.append(VCARD_DATA_SEPARATOR);
- // Empty data.
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_COL_SEPARATOR);
- }
-
- if (contactData.mTel.size() > 0) {
- for (TelData telData : contactData.mTel) {
- appendVCardTelephoneLine(builder, telData.mType,
- telData.mLabel, telData.mValue);
- }
- } else if (isDoCoMo) {
- appendVCardTelephoneLine(builder, Contacts.Phones.TYPE_HOME, "", "");
- }
-
- if (contactData.mEmail.size() > 0) {
- for (EmailData emailData : contactData.mEmail) {
- appendVCardEmailLine(builder, emailData.mType,
- emailData.mLabel, emailData.mValue);
- }
- } else if (isDoCoMo) {
- appendVCardEmailLine(builder, Contacts.ContactMethods.TYPE_HOME, "", "");
- }
-
- if (isDoCoMo) {
- appendVCardAddressLinesForDoCoMo(builder, contactData);
- } else {
- appendVCardAddressLinesForGeneric(builder, contactData);
- }
-
- if (!TextUtils.isEmpty(contactData.mOrg)) {
- appendVCardLine(builder, VCARD_PROPERTY_ORG, contactData.mOrg, true, true);
- }
-
- if (!TextUtils.isEmpty(contactData.mTitle)) {
- appendVCardLine(builder, VCARD_PROPERTY_TITLE, contactData.mTitle, true, true);
- }
-
- if (!TextUtils.isEmpty(contactData.mNote)) {
- appendVCardLine(builder, VCARD_PROPERTY_NOTE, contactData.mNote, true, true);
- }
-
- if ((contactData.mPhoto != null) && (contactData.mPhoto.length() > 0)) {
- // Note that contactData.mPhoto is already BASE64-encoded.
- appendVCardPhotoLine(builder, contactData.mPhoto, contactData.mPhotoType);
- }
-
- appendVCardExtension(builder, contactData, VCARD_PROPERTY_BDAY, isDoCoMo);
-
- // XXX: URL may have non-ascii chars. Should we add charset?
- appendVCardExtension(builder, contactData, VCARD_PROPERTY_URL, isDoCoMo);
-
- if (isDoCoMo) {
- if (contactData.mExtensions.containsKey(VCARD_PROPERTY_X_CLASS)) {
- appendVCardExtension(builder, contactData, VCARD_PROPERTY_X_CLASS, true);
- } else {
- appendVCardLine(builder, VCARD_PROPERTY_X_CLASS, VCARD_DATA_PUBLIC);
- }
- appendVCardExtension(builder, contactData, VCARD_PROPERTY_X_REDUCTION, true);
- appendVCardExtension(builder, contactData, VCARD_PROPERTY_X_NO, true);
- appendVCardExtension(builder, contactData, VCARD_PROPERTY_X_DCM_HMN_MODE, true);
- }
-
- appendVCardLine(builder, VCARD_PROPERTY_END, VCARD_DATA_VCARD);
-
- return builder.toString();
- }
-
- private void appendVCardAddressLinesForGeneric(StringBuilder builder, ContactData contactData) {
- for (AddressData addr : contactData.mAddr) {
- appendVCardAddressLine(builder, addr.mType, addr.mLabel, addr.mValue);
- }
- }
-
- private void appendVCardAddressLinesForDoCoMo(StringBuilder builder, ContactData contactData) {
- boolean isAddrSet = false;
- for (AddressData addr : contactData.mAddr) {
- if ((!isAddrSet) && (addr.mType == Contacts.ContactMethods.TYPE_HOME)) {
- appendVCardAddressLine(builder, addr.mType, addr.mLabel,
- addr.mValue);
- isAddrSet = true;
- break;
- }
- }
- if (!isAddrSet) {
- for (AddressData addr : contactData.mAddr) {
- if ((!isAddrSet) && (addr.mType == Contacts.ContactMethods.TYPE_WORK)) {
- appendVCardAddressLine(builder, addr.mType, addr.mLabel,
- addr.mValue);
- isAddrSet = true;
- break;
- }
- }
- }
- if (!isAddrSet) {
- for (AddressData addr : contactData.mAddr) {
- if ((!isAddrSet) && (addr.mType == Contacts.ContactMethods.TYPE_OTHER)) {
- appendVCardAddressLine(builder, addr.mType, addr.mLabel,
- addr.mValue);
- isAddrSet = true;
- break;
- }
- }
- }
- if (!isAddrSet) {
- for (AddressData addr : contactData.mAddr) {
- if ((!isAddrSet) && (addr.mType == Contacts.ContactMethods.TYPE_CUSTOM)) {
- appendVCardAddressLine(builder, addr.mType, addr.mLabel,
- addr.mValue);
- isAddrSet = true;
- break;
- }
- }
- }
- if (!isAddrSet) {
- appendVCardAddressLine(builder, Contacts.ContactMethods.TYPE_HOME, "", "");
- }
- }
-
- private void appendVCardPhotoLine(StringBuilder builder, String encodedData, String type) {
- StringBuilder tmpBuilder = new StringBuilder();
- tmpBuilder.append(VCARD_PROPERTY_PHOTO);
- tmpBuilder.append(VCARD_ATTR_SEPARATOR);
- tmpBuilder.append(VCARD_ATTR_ENCODING_BASE64_V21);
- tmpBuilder.append(VCARD_ATTR_SEPARATOR);
- tmpBuilder.append("TYPE=");
- tmpBuilder.append(type);
- tmpBuilder.append(VCARD_DATA_SEPARATOR);
- tmpBuilder.append(encodedData);
-
- String tmpStr = tmpBuilder.toString();
- tmpBuilder = new StringBuilder();
- int lineCount = 0;
- for (int i = 0; i < tmpStr.length(); i++) {
- tmpBuilder.append(tmpStr.charAt(i));
- lineCount++;
- if (lineCount > 72) {
- tmpBuilder.append(VCARD_COL_SEPARATOR);
- tmpBuilder.append(VCARD_WS);
- lineCount = 0;
- }
- }
- builder.append(tmpBuilder.toString());
- builder.append(VCARD_COL_SEPARATOR);
- builder.append(VCARD_COL_SEPARATOR);
- }
-
- private void appendVCardAddressLine(StringBuilder builder,
- int type, String label, String rawData) {
- builder.append(VCARD_PROPERTY_ADR);
- builder.append(VCARD_ATTR_SEPARATOR);
-
- boolean dataExists = !TextUtils.isEmpty(rawData);
-
- switch(type) {
- case Contacts.ContactMethods.TYPE_HOME:
- builder.append(VCARD_ATTR_HOME);
- if (dataExists) {
- builder.append(VCARD_ATTR_SEPARATOR);
- }
- break;
- case Contacts.ContactMethods.TYPE_WORK:
- builder.append(VCARD_ATTR_WORK);
- if (dataExists) {
- builder.append(VCARD_ATTR_SEPARATOR);
- }
- break;
- case Contacts.ContactMethods.TYPE_CUSTOM:
- // Ignore custom value since
- // - it may violate vCard spec
- // - it may contain non-ASCII characters
- // TODO: fix this.
- //
- // builder.append(label);
- // builder.append(VCARD_DATA_SEPARATOR);
- // break;
- case Contacts.ContactMethods.TYPE_OTHER:
- default:
- // Ignore other methods.
- // TODO: fix this.
- break;
- }
-
- if (dataExists) {
- builder.append(mVCardAttributeCharset);
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(VCARD_ATTR_ENCODING_QP);
- }
- builder.append(VCARD_DATA_SEPARATOR);
- if (dataExists) {
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(encodeQuotedPrintable(rawData));
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- builder.append(VCARD_ITEM_SEPARATOR);
- }
- builder.append(VCARD_COL_SEPARATOR);
- }
-
- private void appendVCardEmailLine(StringBuilder builder, int type, String label, String data) {
- builder.append(VCARD_PROPERTY_EMAIL);
- builder.append(VCARD_ATTR_SEPARATOR);
-
- switch(type) {
- case Contacts.ContactMethods.TYPE_CUSTOM:
- if (label.equals(Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME)) {
- builder.append(VCARD_ATTR_CELL);
- } else {
- // Ignore custom value.
- builder.append(VCARD_ATTR_INTERNET);
- }
- break;
- case Contacts.ContactMethods.TYPE_HOME:
- builder.append(VCARD_ATTR_HOME);
- break;
- case Contacts.ContactMethods.TYPE_WORK:
- builder.append(VCARD_ATTR_WORK);
- break;
- case Contacts.ContactMethods.TYPE_OTHER:
- default:
- builder.append(VCARD_ATTR_INTERNET);
- break;
- }
-
- builder.append(VCARD_DATA_SEPARATOR);
- builder.append(data);
- builder.append(VCARD_COL_SEPARATOR);
- }
-
- private void appendVCardTelephoneLine(StringBuilder builder,
- int type, String label, String data) {
- builder.append(VCARD_PROPERTY_TEL);
- builder.append(VCARD_ATTR_SEPARATOR);
-
- switch(type) {
- case Contacts.Phones.TYPE_CUSTOM:
- // Ignore custom label.
- builder.append(VCARD_ATTR_VOICE);
- break;
- case Contacts.Phones.TYPE_HOME:
- builder.append(VCARD_ATTR_HOME);
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(VCARD_ATTR_VOICE);
- break;
- case Contacts.Phones.TYPE_MOBILE:
- builder.append(VCARD_ATTR_CELL);
- break;
- case Contacts.Phones.TYPE_WORK:
- builder.append(VCARD_ATTR_WORK);
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(VCARD_ATTR_VOICE);
- break;
- case Contacts.Phones.TYPE_FAX_WORK:
- builder.append(VCARD_ATTR_WORK);
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(VCARD_ATTR_FAX);
- break;
- case Contacts.Phones.TYPE_FAX_HOME:
- builder.append(VCARD_ATTR_HOME);
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(VCARD_ATTR_FAX);
- break;
- case Contacts.Phones.TYPE_PAGER:
- builder.append(VCARD_ATTR_VOICE);
- break;
- case Contacts.Phones.TYPE_OTHER:
- builder.append(VCARD_ATTR_VOICE);
- break;
- default:
- builder.append(VCARD_ATTR_VOICE);
- break;
- }
-
- builder.append(VCARD_DATA_SEPARATOR);
- builder.append(data);
- builder.append(VCARD_COL_SEPARATOR);
- }
-
- private void appendVCardExtension(StringBuilder builder, ContactData contactData,
- String propertyName, boolean mustEmitSomething) {
- if (contactData.mExtensions.containsKey(propertyName)) {
- PropertyNode propertyNode =
- PropertyNode.decode(contactData.mExtensions.get(propertyName));
- appendVCardLine(builder, propertyName, propertyNode.propValue);
- } else if (mustEmitSomething) {
- appendVCardLine(builder, propertyName, "");
- }
- }
-
- private void appendVCardLine(StringBuilder builder, String propertyName, String data) {
- appendVCardLine(builder, propertyName, data, false, false);
- }
-
- private void appendVCardLine(StringBuilder builder, String field, String data,
- boolean needCharset, boolean needQuotedPrintable) {
- builder.append(field);
- if (needCharset) {
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(mVCardAttributeCharset);
- }
-
- if (needQuotedPrintable) {
- builder.append(VCARD_ATTR_SEPARATOR);
- builder.append(VCARD_ATTR_ENCODING_QP);
- data = encodeQuotedPrintable(data);
- }
-
- builder.append(VCARD_DATA_SEPARATOR);
- builder.append(data);
- builder.append(VCARD_COL_SEPARATOR);
- }
-
- // TODO: Replace with the method in Base64 class.
- private static char PAD = '=';
- private static final char[] ENCODE64 = {
- 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
- 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
- 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
- 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
- };
-
- private String encodeBase64(byte[] data) {
- if (data == null) {
- return "";
- }
-
- char[] charBuffer = new char[(data.length + 2) / 3 * 4];
- int position = 0;
- int _3byte = 0;
- for (int i=0; i<data.length-2; i+=3) {
- _3byte = ((data[i] & 0xFF) << 16) + ((data[i+1] & 0xFF) << 8) + (data[i+2] & 0xFF);
- charBuffer[position++] = ENCODE64[_3byte >> 18];
- charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
- charBuffer[position++] = ENCODE64[(_3byte >> 6) & 0x3F];
- charBuffer[position++] = ENCODE64[_3byte & 0x3F];
- }
- switch(data.length % 3) {
- case 1: // [111111][11 0000][0000 00][000000]
- _3byte = ((data[data.length-1] & 0xFF) << 16);
- charBuffer[position++] = ENCODE64[_3byte >> 18];
- charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
- charBuffer[position++] = PAD;
- charBuffer[position++] = PAD;
- break;
- case 2: // [111111][11 1111][1111 00][000000]
- _3byte = ((data[data.length-2] & 0xFF) << 16) + ((data[data.length-1] & 0xFF) << 8);
- charBuffer[position++] = ENCODE64[_3byte >> 18];
- charBuffer[position++] = ENCODE64[(_3byte >> 12) & 0x3F];
- charBuffer[position++] = ENCODE64[(_3byte >> 6) & 0x3F];
- charBuffer[position++] = PAD;
- break;
- }
-
- return new String(charBuffer);
- }
-
- private String encodeQuotedPrintable(String str) {
- {
- // Replace "\n" and "\r" with "\r\n".
- StringBuilder tmpBuilder = new StringBuilder();
- int length = str.length();
- for (int i = 0; i < length; i++) {
- char ch = str.charAt(i);
- if (ch == '\r') {
- if (i + 1 < length && str.charAt(i + 1) == '\n') {
- i++;
- }
- tmpBuilder.append("\r\n");
- } else if (ch == '\n') {
- tmpBuilder.append("\r\n");
- } else {
- tmpBuilder.append(str.charAt(i));
- }
- }
- str = tmpBuilder.toString();
- }
-
- StringBuilder builder = new StringBuilder();
- int index = 0;
- int lineCount = 0;
- byte[] strArray = null;
-
- try {
- strArray = str.getBytes(mCharsetString);
- } catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Charset " + mCharsetString + " cannot be used. " +
- "Try default charset");
- strArray = str.getBytes();
- }
- while (index < strArray.length) {
- builder.append(String.format("=%02X", strArray[index]));
- index += 1;
- lineCount += 3;
-
- if (lineCount >= 67) {
- // Specification requires CRLF must be inserted before the length of the line
- // becomes more than 76.
- // Assuming that the next character is a multi-byte character, it will become
- // 6 bytes.
- // 76 - 6 - 3 = 67
- builder.append("=\r\n");
- lineCount = 0;
- }
- }
-
- return builder.toString();
- }
-
- // TODO: replace this with ContactStruct
- public class ContactData {
- private String mName = "";
- private String mPhoneticName = "";
- private ArrayList<TelData> mTel = new ArrayList<TelData>();
- private ArrayList<EmailData> mEmail = new ArrayList<EmailData>();
- private ArrayList<AddressData> mAddr = new ArrayList<AddressData>();
- private String mOrg = "";
- private String mTitle = "";
- private String mNote = "";
- private String mPhoto = "";
- private String mPhotoType = "JPG"; // Default
- private Map<String, String> mExtensions = new HashMap<String, String>();
-
- public boolean isEmptyName() {
- return TextUtils.isEmpty(mName);
- }
- }
-
- private class AddressData {
- private int mType;
- private String mLabel;
- private String mValue;
-
- public AddressData(int type, String label, String value) {
- mType = type;
- mLabel = label;
- mValue = value;
- }
- }
-
- private class EmailData {
- private int mType;
- private String mLabel;
- private String mValue;
-
- public EmailData(int type, String label, String value) {
- mType = type;
- mLabel = label;
- mValue = value;
- }
- }
-
- private class TelData {
- private int mType;
- private String mLabel;
- private String mValue;
-
- public TelData(int type, String label, String value) {
- mType = type;
- mLabel = label;
- mValue = value;
- }
- }
-}
-
-/**
- * TextUtils especially for Japanese.
- * TODO: make this in android.text in the future
- */
-class JapaneseUtils {
- static private final Map<Character, String> sHalfWidthMap =
- new HashMap<Character, String>();
-
- static {
- // There's no logical mapping rule in Unicode. Sigh.
- sHalfWidthMap.put('\u3001', "\uFF64");
- sHalfWidthMap.put('\u3002', "\uFF61");
- sHalfWidthMap.put('\u300C', "\uFF62");
- sHalfWidthMap.put('\u300D', "\uFF63");
- sHalfWidthMap.put('\u301C', "~");
- sHalfWidthMap.put('\u3041', "\uFF67");
- sHalfWidthMap.put('\u3042', "\uFF71");
- sHalfWidthMap.put('\u3043', "\uFF68");
- sHalfWidthMap.put('\u3044', "\uFF72");
- sHalfWidthMap.put('\u3045', "\uFF69");
- sHalfWidthMap.put('\u3046', "\uFF73");
- sHalfWidthMap.put('\u3047', "\uFF6A");
- sHalfWidthMap.put('\u3048', "\uFF74");
- sHalfWidthMap.put('\u3049', "\uFF6B");
- sHalfWidthMap.put('\u304A', "\uFF75");
- sHalfWidthMap.put('\u304B', "\uFF76");
- sHalfWidthMap.put('\u304C', "\uFF76\uFF9E");
- sHalfWidthMap.put('\u304D', "\uFF77");
- sHalfWidthMap.put('\u304E', "\uFF77\uFF9E");
- sHalfWidthMap.put('\u304F', "\uFF78");
- sHalfWidthMap.put('\u3050', "\uFF78\uFF9E");
- sHalfWidthMap.put('\u3051', "\uFF79");
- sHalfWidthMap.put('\u3052', "\uFF79\uFF9E");
- sHalfWidthMap.put('\u3053', "\uFF7A");
- sHalfWidthMap.put('\u3054', "\uFF7A\uFF9E");
- sHalfWidthMap.put('\u3055', "\uFF7B");
- sHalfWidthMap.put('\u3056', "\uFF7B\uFF9E");
- sHalfWidthMap.put('\u3057', "\uFF7C");
- sHalfWidthMap.put('\u3058', "\uFF7C\uFF9E");
- sHalfWidthMap.put('\u3059', "\uFF7D");
- sHalfWidthMap.put('\u305A', "\uFF7D\uFF9E");
- sHalfWidthMap.put('\u305B', "\uFF7E");
- sHalfWidthMap.put('\u305C', "\uFF7E\uFF9E");
- sHalfWidthMap.put('\u305D', "\uFF7F");
- sHalfWidthMap.put('\u305E', "\uFF7F\uFF9E");
- sHalfWidthMap.put('\u305F', "\uFF80");
- sHalfWidthMap.put('\u3060', "\uFF80\uFF9E");
- sHalfWidthMap.put('\u3061', "\uFF81");
- sHalfWidthMap.put('\u3062', "\uFF81\uFF9E");
- sHalfWidthMap.put('\u3063', "\uFF6F");
- sHalfWidthMap.put('\u3064', "\uFF82");
- sHalfWidthMap.put('\u3065', "\uFF82\uFF9E");
- sHalfWidthMap.put('\u3066', "\uFF83");
- sHalfWidthMap.put('\u3067', "\uFF83\uFF9E");
- sHalfWidthMap.put('\u3068', "\uFF84");
- sHalfWidthMap.put('\u3069', "\uFF84\uFF9E");
- sHalfWidthMap.put('\u306A', "\uFF85");
- sHalfWidthMap.put('\u306B', "\uFF86");
- sHalfWidthMap.put('\u306C', "\uFF87");
- sHalfWidthMap.put('\u306D', "\uFF88");
- sHalfWidthMap.put('\u306E', "\uFF89");
- sHalfWidthMap.put('\u306F', "\uFF8A");
- sHalfWidthMap.put('\u3070', "\uFF8A\uFF9E");
- sHalfWidthMap.put('\u3071', "\uFF8A\uFF9F");
- sHalfWidthMap.put('\u3072', "\uFF8B");
- sHalfWidthMap.put('\u3073', "\uFF8B\uFF9E");
- sHalfWidthMap.put('\u3074', "\uFF8B\uFF9F");
- sHalfWidthMap.put('\u3075', "\uFF8C");
- sHalfWidthMap.put('\u3076', "\uFF8C\uFF9E");
- sHalfWidthMap.put('\u3077', "\uFF8C\uFF9F");
- sHalfWidthMap.put('\u3078', "\uFF8D");
- sHalfWidthMap.put('\u3079', "\uFF8D\uFF9E");
- sHalfWidthMap.put('\u307A', "\uFF8D\uFF9F");
- sHalfWidthMap.put('\u307B', "\uFF8E");
- sHalfWidthMap.put('\u307C', "\uFF8E\uFF9E");
- sHalfWidthMap.put('\u307D', "\uFF8E\uFF9F");
- sHalfWidthMap.put('\u307E', "\uFF8F");
- sHalfWidthMap.put('\u307F', "\uFF90");
- sHalfWidthMap.put('\u3080', "\uFF91");
- sHalfWidthMap.put('\u3081', "\uFF92");
- sHalfWidthMap.put('\u3082', "\uFF93");
- sHalfWidthMap.put('\u3083', "\uFF6C");
- sHalfWidthMap.put('\u3084', "\uFF94");
- sHalfWidthMap.put('\u3085', "\uFF6D");
- sHalfWidthMap.put('\u3086', "\uFF95");
- sHalfWidthMap.put('\u3087', "\uFF6E");
- sHalfWidthMap.put('\u3088', "\uFF96");
- sHalfWidthMap.put('\u3089', "\uFF97");
- sHalfWidthMap.put('\u308A', "\uFF98");
- sHalfWidthMap.put('\u308B', "\uFF99");
- sHalfWidthMap.put('\u308C', "\uFF9A");
- sHalfWidthMap.put('\u308D', "\uFF9B");
- sHalfWidthMap.put('\u308E', "\uFF9C");
- sHalfWidthMap.put('\u308F', "\uFF9C");
- sHalfWidthMap.put('\u3090', "\uFF72");
- sHalfWidthMap.put('\u3091', "\uFF74");
- sHalfWidthMap.put('\u3092', "\uFF66");
- sHalfWidthMap.put('\u3093', "\uFF9D");
- sHalfWidthMap.put('\u309B', "\uFF9E");
- sHalfWidthMap.put('\u309C', "\uFF9F");
- sHalfWidthMap.put('\u30A1', "\uFF67");
- sHalfWidthMap.put('\u30A2', "\uFF71");
- sHalfWidthMap.put('\u30A3', "\uFF68");
- sHalfWidthMap.put('\u30A4', "\uFF72");
- sHalfWidthMap.put('\u30A5', "\uFF69");
- sHalfWidthMap.put('\u30A6', "\uFF73");
- sHalfWidthMap.put('\u30A7', "\uFF6A");
- sHalfWidthMap.put('\u30A8', "\uFF74");
- sHalfWidthMap.put('\u30A9', "\uFF6B");
- sHalfWidthMap.put('\u30AA', "\uFF75");
- sHalfWidthMap.put('\u30AB', "\uFF76");
- sHalfWidthMap.put('\u30AC', "\uFF76\uFF9E");
- sHalfWidthMap.put('\u30AD', "\uFF77");
- sHalfWidthMap.put('\u30AE', "\uFF77\uFF9E");
- sHalfWidthMap.put('\u30AF', "\uFF78");
- sHalfWidthMap.put('\u30B0', "\uFF78\uFF9E");
- sHalfWidthMap.put('\u30B1', "\uFF79");
- sHalfWidthMap.put('\u30B2', "\uFF79\uFF9E");
- sHalfWidthMap.put('\u30B3', "\uFF7A");
- sHalfWidthMap.put('\u30B4', "\uFF7A\uFF9E");
- sHalfWidthMap.put('\u30B5', "\uFF7B");
- sHalfWidthMap.put('\u30B6', "\uFF7B\uFF9E");
- sHalfWidthMap.put('\u30B7', "\uFF7C");
- sHalfWidthMap.put('\u30B8', "\uFF7C\uFF9E");
- sHalfWidthMap.put('\u30B9', "\uFF7D");
- sHalfWidthMap.put('\u30BA', "\uFF7D\uFF9E");
- sHalfWidthMap.put('\u30BB', "\uFF7E");
- sHalfWidthMap.put('\u30BC', "\uFF7E\uFF9E");
- sHalfWidthMap.put('\u30BD', "\uFF7F");
- sHalfWidthMap.put('\u30BE', "\uFF7F\uFF9E");
- sHalfWidthMap.put('\u30BF', "\uFF80");
- sHalfWidthMap.put('\u30C0', "\uFF80\uFF9E");
- sHalfWidthMap.put('\u30C1', "\uFF81");
- sHalfWidthMap.put('\u30C2', "\uFF81\uFF9E");
- sHalfWidthMap.put('\u30C3', "\uFF6F");
- sHalfWidthMap.put('\u30C4', "\uFF82");
- sHalfWidthMap.put('\u30C5', "\uFF82\uFF9E");
- sHalfWidthMap.put('\u30C6', "\uFF83");
- sHalfWidthMap.put('\u30C7', "\uFF83\uFF9E");
- sHalfWidthMap.put('\u30C8', "\uFF84");
- sHalfWidthMap.put('\u30C9', "\uFF84\uFF9E");
- sHalfWidthMap.put('\u30CA', "\uFF85");
- sHalfWidthMap.put('\u30CB', "\uFF86");
- sHalfWidthMap.put('\u30CC', "\uFF87");
- sHalfWidthMap.put('\u30CD', "\uFF88");
- sHalfWidthMap.put('\u30CE', "\uFF89");
- sHalfWidthMap.put('\u30CF', "\uFF8A");
- sHalfWidthMap.put('\u30D0', "\uFF8A\uFF9E");
- sHalfWidthMap.put('\u30D1', "\uFF8A\uFF9F");
- sHalfWidthMap.put('\u30D2', "\uFF8B");
- sHalfWidthMap.put('\u30D3', "\uFF8B\uFF9E");
- sHalfWidthMap.put('\u30D4', "\uFF8B\uFF9F");
- sHalfWidthMap.put('\u30D5', "\uFF8C");
- sHalfWidthMap.put('\u30D6', "\uFF8C\uFF9E");
- sHalfWidthMap.put('\u30D7', "\uFF8C\uFF9F");
- sHalfWidthMap.put('\u30D8', "\uFF8D");
- sHalfWidthMap.put('\u30D9', "\uFF8D\uFF9E");
- sHalfWidthMap.put('\u30DA', "\uFF8D\uFF9F");
- sHalfWidthMap.put('\u30DB', "\uFF8E");
- sHalfWidthMap.put('\u30DC', "\uFF8E\uFF9E");
- sHalfWidthMap.put('\u30DD', "\uFF8E\uFF9F");
- sHalfWidthMap.put('\u30DE', "\uFF8F");
- sHalfWidthMap.put('\u30DF', "\uFF90");
- sHalfWidthMap.put('\u30E0', "\uFF91");
- sHalfWidthMap.put('\u30E1', "\uFF92");
- sHalfWidthMap.put('\u30E2', "\uFF93");
- sHalfWidthMap.put('\u30E3', "\uFF6C");
- sHalfWidthMap.put('\u30E4', "\uFF94");
- sHalfWidthMap.put('\u30E5', "\uFF6D");
- sHalfWidthMap.put('\u30E6', "\uFF95");
- sHalfWidthMap.put('\u30E7', "\uFF6E");
- sHalfWidthMap.put('\u30E8', "\uFF96");
- sHalfWidthMap.put('\u30E9', "\uFF97");
- sHalfWidthMap.put('\u30EA', "\uFF98");
- sHalfWidthMap.put('\u30EB', "\uFF99");
- sHalfWidthMap.put('\u30EC', "\uFF9A");
- sHalfWidthMap.put('\u30ED', "\uFF9B");
- sHalfWidthMap.put('\u30EE', "\uFF9C");
- sHalfWidthMap.put('\u30EF', "\uFF9C");
- sHalfWidthMap.put('\u30F0', "\uFF72");
- sHalfWidthMap.put('\u30F1', "\uFF74");
- sHalfWidthMap.put('\u30F2', "\uFF66");
- sHalfWidthMap.put('\u30F3', "\uFF9D");
- sHalfWidthMap.put('\u30F4', "\uFF73\uFF9E");
- sHalfWidthMap.put('\u30F5', "\uFF76");
- sHalfWidthMap.put('\u30F6', "\uFF79");
- sHalfWidthMap.put('\u30FB', "\uFF65");
- sHalfWidthMap.put('\u30FC', "\uFF70");
- sHalfWidthMap.put('\uFF01', "!");
- sHalfWidthMap.put('\uFF02', "\"");
- sHalfWidthMap.put('\uFF03', "#");
- sHalfWidthMap.put('\uFF04', "$");
- sHalfWidthMap.put('\uFF05', "%");
- sHalfWidthMap.put('\uFF06', "&");
- sHalfWidthMap.put('\uFF07', "'");
- sHalfWidthMap.put('\uFF08', "(");
- sHalfWidthMap.put('\uFF09', ")");
- sHalfWidthMap.put('\uFF0A', "*");
- sHalfWidthMap.put('\uFF0B', "+");
- sHalfWidthMap.put('\uFF0C', ",");
- sHalfWidthMap.put('\uFF0D', "-");
- sHalfWidthMap.put('\uFF0E', ".");
- sHalfWidthMap.put('\uFF0F', "/");
- sHalfWidthMap.put('\uFF10', "0");
- sHalfWidthMap.put('\uFF11', "1");
- sHalfWidthMap.put('\uFF12', "2");
- sHalfWidthMap.put('\uFF13', "3");
- sHalfWidthMap.put('\uFF14', "4");
- sHalfWidthMap.put('\uFF15', "5");
- sHalfWidthMap.put('\uFF16', "6");
- sHalfWidthMap.put('\uFF17', "7");
- sHalfWidthMap.put('\uFF18', "8");
- sHalfWidthMap.put('\uFF19', "9");
- sHalfWidthMap.put('\uFF1A', ":");
- sHalfWidthMap.put('\uFF1B', ";");
- sHalfWidthMap.put('\uFF1C', "<");
- sHalfWidthMap.put('\uFF1D', "=");
- sHalfWidthMap.put('\uFF1E', ">");
- sHalfWidthMap.put('\uFF1F', "?");
- sHalfWidthMap.put('\uFF20', "@");
- sHalfWidthMap.put('\uFF21', "A");
- sHalfWidthMap.put('\uFF22', "B");
- sHalfWidthMap.put('\uFF23', "C");
- sHalfWidthMap.put('\uFF24', "D");
- sHalfWidthMap.put('\uFF25', "E");
- sHalfWidthMap.put('\uFF26', "F");
- sHalfWidthMap.put('\uFF27', "G");
- sHalfWidthMap.put('\uFF28', "H");
- sHalfWidthMap.put('\uFF29', "I");
- sHalfWidthMap.put('\uFF2A', "J");
- sHalfWidthMap.put('\uFF2B', "K");
- sHalfWidthMap.put('\uFF2C', "L");
- sHalfWidthMap.put('\uFF2D', "M");
- sHalfWidthMap.put('\uFF2E', "N");
- sHalfWidthMap.put('\uFF2F', "O");
- sHalfWidthMap.put('\uFF30', "P");
- sHalfWidthMap.put('\uFF31', "Q");
- sHalfWidthMap.put('\uFF32', "R");
- sHalfWidthMap.put('\uFF33', "S");
- sHalfWidthMap.put('\uFF34', "T");
- sHalfWidthMap.put('\uFF35', "U");
- sHalfWidthMap.put('\uFF36', "V");
- sHalfWidthMap.put('\uFF37', "W");
- sHalfWidthMap.put('\uFF38', "X");
- sHalfWidthMap.put('\uFF39', "Y");
- sHalfWidthMap.put('\uFF3A', "Z");
- sHalfWidthMap.put('\uFF3B', "[");
- sHalfWidthMap.put('\uFF3C', "\\");
- sHalfWidthMap.put('\uFF3D', "]");
- sHalfWidthMap.put('\uFF3E', "^");
- sHalfWidthMap.put('\uFF3F', "_");
- sHalfWidthMap.put('\uFF41', "a");
- sHalfWidthMap.put('\uFF42', "b");
- sHalfWidthMap.put('\uFF43', "c");
- sHalfWidthMap.put('\uFF44', "d");
- sHalfWidthMap.put('\uFF45', "e");
- sHalfWidthMap.put('\uFF46', "f");
- sHalfWidthMap.put('\uFF47', "g");
- sHalfWidthMap.put('\uFF48', "h");
- sHalfWidthMap.put('\uFF49', "i");
- sHalfWidthMap.put('\uFF4A', "j");
- sHalfWidthMap.put('\uFF4B', "k");
- sHalfWidthMap.put('\uFF4C', "l");
- sHalfWidthMap.put('\uFF4D', "m");
- sHalfWidthMap.put('\uFF4E', "n");
- sHalfWidthMap.put('\uFF4F', "o");
- sHalfWidthMap.put('\uFF50', "p");
- sHalfWidthMap.put('\uFF51', "q");
- sHalfWidthMap.put('\uFF52', "r");
- sHalfWidthMap.put('\uFF53', "s");
- sHalfWidthMap.put('\uFF54', "t");
- sHalfWidthMap.put('\uFF55', "u");
- sHalfWidthMap.put('\uFF56', "v");
- sHalfWidthMap.put('\uFF57', "w");
- sHalfWidthMap.put('\uFF58', "x");
- sHalfWidthMap.put('\uFF59', "y");
- sHalfWidthMap.put('\uFF5A', "z");
- sHalfWidthMap.put('\uFF5B', "{");
- sHalfWidthMap.put('\uFF5C', "|");
- sHalfWidthMap.put('\uFF5D', "}");
- sHalfWidthMap.put('\uFF5E', "~");
- sHalfWidthMap.put('\uFF61', "\uFF61");
- sHalfWidthMap.put('\uFF62', "\uFF62");
- sHalfWidthMap.put('\uFF63', "\uFF63");
- sHalfWidthMap.put('\uFF64', "\uFF64");
- sHalfWidthMap.put('\uFF65', "\uFF65");
- sHalfWidthMap.put('\uFF66', "\uFF66");
- sHalfWidthMap.put('\uFF67', "\uFF67");
- sHalfWidthMap.put('\uFF68', "\uFF68");
- sHalfWidthMap.put('\uFF69', "\uFF69");
- sHalfWidthMap.put('\uFF6A', "\uFF6A");
- sHalfWidthMap.put('\uFF6B', "\uFF6B");
- sHalfWidthMap.put('\uFF6C', "\uFF6C");
- sHalfWidthMap.put('\uFF6D', "\uFF6D");
- sHalfWidthMap.put('\uFF6E', "\uFF6E");
- sHalfWidthMap.put('\uFF6F', "\uFF6F");
- sHalfWidthMap.put('\uFF70', "\uFF70");
- sHalfWidthMap.put('\uFF71', "\uFF71");
- sHalfWidthMap.put('\uFF72', "\uFF72");
- sHalfWidthMap.put('\uFF73', "\uFF73");
- sHalfWidthMap.put('\uFF74', "\uFF74");
- sHalfWidthMap.put('\uFF75', "\uFF75");
- sHalfWidthMap.put('\uFF76', "\uFF76");
- sHalfWidthMap.put('\uFF77', "\uFF77");
- sHalfWidthMap.put('\uFF78', "\uFF78");
- sHalfWidthMap.put('\uFF79', "\uFF79");
- sHalfWidthMap.put('\uFF7A', "\uFF7A");
- sHalfWidthMap.put('\uFF7B', "\uFF7B");
- sHalfWidthMap.put('\uFF7C', "\uFF7C");
- sHalfWidthMap.put('\uFF7D', "\uFF7D");
- sHalfWidthMap.put('\uFF7E', "\uFF7E");
- sHalfWidthMap.put('\uFF7F', "\uFF7F");
- sHalfWidthMap.put('\uFF80', "\uFF80");
- sHalfWidthMap.put('\uFF81', "\uFF81");
- sHalfWidthMap.put('\uFF82', "\uFF82");
- sHalfWidthMap.put('\uFF83', "\uFF83");
- sHalfWidthMap.put('\uFF84', "\uFF84");
- sHalfWidthMap.put('\uFF85', "\uFF85");
- sHalfWidthMap.put('\uFF86', "\uFF86");
- sHalfWidthMap.put('\uFF87', "\uFF87");
- sHalfWidthMap.put('\uFF88', "\uFF88");
- sHalfWidthMap.put('\uFF89', "\uFF89");
- sHalfWidthMap.put('\uFF8A', "\uFF8A");
- sHalfWidthMap.put('\uFF8B', "\uFF8B");
- sHalfWidthMap.put('\uFF8C', "\uFF8C");
- sHalfWidthMap.put('\uFF8D', "\uFF8D");
- sHalfWidthMap.put('\uFF8E', "\uFF8E");
- sHalfWidthMap.put('\uFF8F', "\uFF8F");
- sHalfWidthMap.put('\uFF90', "\uFF90");
- sHalfWidthMap.put('\uFF91', "\uFF91");
- sHalfWidthMap.put('\uFF92', "\uFF92");
- sHalfWidthMap.put('\uFF93', "\uFF93");
- sHalfWidthMap.put('\uFF94', "\uFF94");
- sHalfWidthMap.put('\uFF95', "\uFF95");
- sHalfWidthMap.put('\uFF96', "\uFF96");
- sHalfWidthMap.put('\uFF97', "\uFF97");
- sHalfWidthMap.put('\uFF98', "\uFF98");
- sHalfWidthMap.put('\uFF99', "\uFF99");
- sHalfWidthMap.put('\uFF9A', "\uFF9A");
- sHalfWidthMap.put('\uFF9B', "\uFF9B");
- sHalfWidthMap.put('\uFF9C', "\uFF9C");
- sHalfWidthMap.put('\uFF9D', "\uFF9D");
- sHalfWidthMap.put('\uFF9E', "\uFF9E");
- sHalfWidthMap.put('\uFF9F', "\uFF9F");
- sHalfWidthMap.put('\uFFE5', "\u005C\u005C");
- }
-
- /**
- * Return half-width version of that character if possible. Return null if not possible
- * @param ch input character
- * @return CharSequence object if the mapping for ch exists. Return null otherwise.
- */
- public static CharSequence tryGetHalfWidthText(char ch) {
- if (sHalfWidthMap.containsKey(ch)) {
- return sHalfWidthMap.get(ch);
- } else {
- return null;
- }
- }
-}
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index 28a82b4..ca3c08a 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -16,132 +16,141 @@
package com.android.contacts;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_CUSTOM_RINGTONE_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_NAME_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_NOTES_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_PHONETIC_NAME_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_PROJECTION;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_SEND_TO_VOICEMAIL_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.CONTACT_STARRED_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_AUX_DATA_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_DATA_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_ID_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_KIND_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_LABEL_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_STATUS_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_TYPE_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.METHODS_WITH_PRESENCE_PROJECTION;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_COMPANY_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_ID_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_LABEL_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_PROJECTION;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_TITLE_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_TYPE_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.PHONES_ID_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.PHONES_ISPRIMARY_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.PHONES_LABEL_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.PHONES_NUMBER_COLUMN;
-import static com.android.contacts.ContactEntryAdapter.PHONES_PROJECTION;
-import static com.android.contacts.ContactEntryAdapter.PHONES_TYPE_COLUMN;
-
+import com.android.contacts.Collapser.Collapsible;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.Sources;
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.ui.EditContactActivity;
+import com.android.contacts.util.Constants;
+import com.android.contacts.util.DataStatus;
+import com.android.contacts.util.NotifyingAsyncQueryHandler;
import com.android.internal.telephony.ITelephony;
+import com.android.internal.widget.ContactHeaderWidget;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.app.ListActivity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Entity;
+import android.content.EntityIterator;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
+import android.content.Entity.NamedContentValues;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.provider.Contacts;
-import android.provider.Im;
-import android.provider.Contacts.ContactMethods;
-import android.provider.Contacts.Organizations;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
-import android.provider.Contacts.Presence;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.AggregationExceptions;
+import android.provider.ContactsContract.CommonDataKinds;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.StatusUpdates;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.Note;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.view.Window;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
-import android.widget.CheckBox;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ListView;
+import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
/**
* Displays the details of a specific contact.
*/
-public class ViewContactActivity extends ListActivity
- implements View.OnCreateContextMenuListener, View.OnClickListener,
- DialogInterface.OnClickListener {
+public class ViewContactActivity extends Activity
+ implements View.OnCreateContextMenuListener, DialogInterface.OnClickListener,
+ AdapterView.OnItemClickListener, NotifyingAsyncQueryHandler.AsyncQueryListener {
private static final String TAG = "ViewContact";
- private static final String SHOW_BARCODE_INTENT = "com.google.zxing.client.android.ENCODE";
private static final boolean SHOW_SEPARATORS = false;
-
- private static final String[] PHONE_KEYS = {
- Contacts.Intents.Insert.PHONE,
- Contacts.Intents.Insert.SECONDARY_PHONE,
- Contacts.Intents.Insert.TERTIARY_PHONE
- };
-
- private static final String[] EMAIL_KEYS = {
- Contacts.Intents.Insert.EMAIL,
- Contacts.Intents.Insert.SECONDARY_EMAIL,
- Contacts.Intents.Insert.TERTIARY_EMAIL
- };
private static final int DIALOG_CONFIRM_DELETE = 1;
+ private static final int DIALOG_CONFIRM_READONLY_DELETE = 2;
+ private static final int DIALOG_CONFIRM_MULTIPLE_DELETE = 3;
+ private static final int DIALOG_CONFIRM_READONLY_HIDE = 4;
- public static final int MENU_ITEM_DELETE = 1;
- public static final int MENU_ITEM_MAKE_DEFAULT = 2;
- public static final int MENU_ITEM_SHOW_BARCODE = 3;
+ private static final int REQUEST_JOIN_CONTACT = 1;
+ private static final int REQUEST_EDIT_CONTACT = 2;
- private Uri mUri;
+ public static final int MENU_ITEM_MAKE_DEFAULT = 3;
+
+ protected Uri mLookupUri;
private ContentResolver mResolver;
private ViewAdapter mAdapter;
private int mNumPhoneNumbers = 0;
+ /**
+ * A list of distinct contact IDs included in the current contact.
+ */
+ private ArrayList<Long> mRawContactIds = new ArrayList<Long>();
+
/* package */ ArrayList<ViewEntry> mPhoneEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ViewEntry> mSmsEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ViewEntry> mEmailEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ViewEntry> mPostalEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ViewEntry> mImEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ViewEntry> mOrganizationEntries = new ArrayList<ViewEntry>();
+ /* package */ ArrayList<ViewEntry> mGroupEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ViewEntry> mOtherEntries = new ArrayList<ViewEntry>();
/* package */ ArrayList<ArrayList<ViewEntry>> mSections = new ArrayList<ArrayList<ViewEntry>>();
private Cursor mCursor;
- private boolean mObserverRegistered;
-
+
+ protected ContactHeaderWidget mContactHeaderWidget;
+ private NotifyingAsyncQueryHandler mHandler;
+
+ protected LayoutInflater mInflater;
+
+ protected int mReadOnlySourcesCnt;
+ protected int mWritableSourcesCnt;
+ protected boolean mAllRestricted;
+
+ protected ArrayList<Long> mWritableRawContactIds = new ArrayList<Long>();
+
+ private static final int TOKEN_ENTITIES = 0;
+ private static final int TOKEN_STATUSES = 1;
+
+ private boolean mHasEntities = false;
+ private boolean mHasStatuses = false;
+
+ private ArrayList<Entity> mEntities = Lists.newArrayList();
+ private HashMap<Long, DataStatus> mStatuses = Maps.newHashMap();
+
private ContentObserver mObserver = new ContentObserver(new Handler()) {
@Override
public boolean deliverSelfNotifications() {
@@ -150,75 +159,55 @@
@Override
public void onChange(boolean selfChange) {
- if (mCursor != null && !mCursor.isClosed()){
- dataChanged();
+ if (mCursor != null && !mCursor.isClosed()) {
+ startEntityQuery();
}
}
};
public void onClick(DialogInterface dialog, int which) {
- if (mCursor != null) {
- if (mObserverRegistered) {
- mCursor.unregisterContentObserver(mObserver);
- mObserverRegistered = false;
- }
- mCursor.close();
- mCursor = null;
- }
- getContentResolver().delete(mUri, null, null);
+ closeCursor();
+ getContentResolver().delete(mLookupUri, null, null);
finish();
}
- public void onClick(View view) {
- if (!mObserverRegistered) {
- return;
- }
- switch (view.getId()) {
- case R.id.star: {
- int oldStarredState = mCursor.getInt(CONTACT_STARRED_COLUMN);
- ContentValues values = new ContentValues(1);
- values.put(People.STARRED, oldStarredState == 1 ? 0 : 1);
- getContentResolver().update(mUri, values, null, null);
- break;
- }
- }
- }
-
- private TextView mNameView;
- private TextView mPhoneticNameView; // may be null in some locales
- private ImageView mPhotoView;
- private int mNoPhotoResource;
- private CheckBox mStarView;
+ private ListView mListView;
private boolean mShowSmsLinksForAllPhones;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- setContentView(R.layout.view_contact);
- getListView().setOnCreateContextMenuListener(this);
+ final Intent intent = getIntent();
+ Uri data = intent.getData();
+ String authority = data.getAuthority();
+ if (ContactsContract.AUTHORITY.equals(authority)) {
+ mLookupUri = data;
+ } else if (android.provider.Contacts.AUTHORITY.equals(authority)) {
+ final long rawContactId = ContentUris.parseId(data);
+ mLookupUri = RawContacts.getContactLookupUri(getContentResolver(),
+ ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
- mNameView = (TextView) findViewById(R.id.name);
- mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name);
- mPhotoView = (ImageView) findViewById(R.id.photo);
- mStarView = (CheckBox) findViewById(R.id.star);
- mStarView.setOnClickListener(this);
-
- // Set the photo with a random "no contact" image
- long now = SystemClock.elapsedRealtime();
- int num = (int) now & 0xf;
- if (num < 9) {
- // Leaning in from right, common
- mNoPhotoResource = R.drawable.ic_contact_picture;
- } else if (num < 14) {
- // Leaning in from left uncommon
- mNoPhotoResource = R.drawable.ic_contact_picture_2;
- } else {
- // Coming in from the top, rare
- mNoPhotoResource = R.drawable.ic_contact_picture_3;
}
+ mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mUri = getIntent().getData();
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.contact_card_layout);
+
+ mContactHeaderWidget = (ContactHeaderWidget) findViewById(R.id.contact_header_widget);
+ mContactHeaderWidget.showStar(true);
+ mContactHeaderWidget.setExcludeMimes(new String[] {
+ Contacts.CONTENT_ITEM_TYPE
+ });
+
+ mHandler = new NotifyingAsyncQueryHandler(this, this);
+
+ mListView = (ListView) findViewById(R.id.contact_data);
+ mListView.setOnCreateContextMenuListener(this);
+ mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
+ mListView.setOnItemClickListener(this);
+ mListView.setEmptyView((ScrollView) findViewById(android.R.id.empty));
+
mResolver = getContentResolver();
// Build the list of sections. The order they're added to mSections dictates the
@@ -229,45 +218,29 @@
mSections.add(mImEntries);
mSections.add(mPostalEntries);
mSections.add(mOrganizationEntries);
+ mSections.add(mGroupEntries);
mSections.add(mOtherEntries);
//TODO Read this value from a preference
mShowSmsLinksForAllPhones = true;
-
- mCursor = mResolver.query(mUri, CONTACT_PROJECTION, null, null, null);
}
@Override
protected void onResume() {
super.onResume();
- mObserverRegistered = true;
- mCursor.registerContentObserver(mObserver);
- dataChanged();
+ startEntityQuery();
}
@Override
protected void onPause() {
super.onPause();
- if (mCursor != null) {
- if (mObserverRegistered) {
- mObserverRegistered = false;
- mCursor.unregisterContentObserver(mObserver);
- }
- mCursor.deactivate();
- }
+ closeCursor();
}
@Override
protected void onDestroy() {
super.onDestroy();
-
- if (mCursor != null) {
- if (mObserverRegistered) {
- mCursor.unregisterContentObserver(mObserver);
- mObserverRegistered = false;
- }
- mCursor.close();
- }
+ closeCursor();
}
@Override
@@ -282,81 +255,208 @@
.setPositiveButton(android.R.string.ok, this)
.setCancelable(false)
.create();
+ case DIALOG_CONFIRM_READONLY_DELETE:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.readOnlyContactDeleteConfirmation)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, this)
+ .setCancelable(false)
+ .create();
+ case DIALOG_CONFIRM_MULTIPLE_DELETE:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.multipleContactDeleteConfirmation)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, this)
+ .setCancelable(false)
+ .create();
+ case DIALOG_CONFIRM_READONLY_HIDE: {
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.readOnlyContactWarning)
+ .setPositiveButton(android.R.string.ok, this)
+ .create();
+ }
+
}
return null;
}
- private void dataChanged() {
- mCursor.requery();
- if (mCursor.moveToFirst()) {
- // Set the name
- String name = mCursor.getString(CONTACT_NAME_COLUMN);
- if (TextUtils.isEmpty(name)) {
- mNameView.setText(getText(android.R.string.unknownName));
- } else {
- mNameView.setText(name);
+ // QUERY CODE //
+ /** {@inheritDoc} */
+ public void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
+ try {
+ // Read incoming entities and consider binding
+ readEntities(iterator);
+ considerBindData();
+ } finally {
+ if (iterator != null) {
+ iterator.close();
}
+ }
+ }
- if (mPhoneticNameView != null) {
- String phoneticName = mCursor.getString(CONTACT_PHONETIC_NAME_COLUMN);
- mPhoneticNameView.setText(phoneticName);
+ /** {@inheritDoc} */
+ public void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ try {
+ // Read available social rows and consider binding
+ readStatuses(cursor);
+ considerBindData();
+ } finally {
+ if (cursor != null) {
+ cursor.close();
}
+ }
+ }
- // Load the photo
- mPhotoView.setImageBitmap(People.loadContactPhoto(this, mUri, mNoPhotoResource,
- null /* use the default options */));
+ private long getRefreshedContactId() {
+ Uri freshContactUri = Contacts.lookupContact(getContentResolver(), mLookupUri);
+ if (freshContactUri != null) {
+ return ContentUris.parseId(freshContactUri);
+ }
+ return -1;
+ }
- // Set the star
- mStarView.setChecked(mCursor.getInt(CONTACT_STARRED_COLUMN) == 1 ? true : false);
-
- // Build up the contact entries
- buildEntries(mCursor);
- if (mAdapter == null) {
- mAdapter = new ViewAdapter(this, mSections);
- setListAdapter(mAdapter);
- } else {
- mAdapter.setSections(mSections, SHOW_SEPARATORS);
+ /**
+ * Read from the given {@link EntityIterator} to build internal set of
+ * {@link #mEntities} for data display.
+ */
+ private synchronized void readEntities(EntityIterator iterator) {
+ mEntities.clear();
+ try {
+ while (iterator.hasNext()) {
+ mEntities.add(iterator.next());
}
- } else {
+ mHasEntities = true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Problem reading contact data: " + e.toString());
+ }
+ }
+
+ /**
+ * Read from the given {@link Cursor} and build a set of {@link DataStatus}
+ * objects to match any valid statuses found.
+ */
+ private synchronized void readStatuses(Cursor cursor) {
+ mStatuses.clear();
+
+ // Walk found statuses, creating internal row for each
+ while (cursor.moveToNext()) {
+ final DataStatus status = new DataStatus(cursor);
+ final long dataId = cursor.getLong(StatusQuery._ID);
+ mStatuses.put(dataId, status);
+ }
+
+ mHasStatuses = true;
+ }
+
+ private synchronized void startEntityQuery() {
+ closeCursor();
+
+ Uri uri = null;
+ if (mLookupUri != null) {
+ mLookupUri = Contacts.getLookupUri(getContentResolver(), mLookupUri);
+ if (mLookupUri != null) {
+ uri = Contacts.lookupContact(getContentResolver(), mLookupUri);
+ }
+ }
+
+ if (uri == null) {
+
+ // TODO either figure out a way to prevent a flash of black background or
+ // use some other UI than a toast
Toast.makeText(this, R.string.invalidContactMessage, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "invalid contact uri: " + mUri);
+ Log.e(TAG, "invalid contact uri: " + mLookupUri);
finish();
+ return;
+ }
+
+ final Uri dataUri = Uri.withAppendedPath(uri, Contacts.Data.CONTENT_DIRECTORY);
+
+ // Keep stub cursor open on side to watch for change events
+ mCursor = mResolver.query(dataUri,
+ new String[] {Contacts.DISPLAY_NAME}, null, null, null);
+ mCursor.registerContentObserver(mObserver);
+
+ final long contactId = ContentUris.parseId(uri);
+
+ // Clear flags and start queries to data and status
+ mHasEntities = false;
+ mHasStatuses = false;
+
+ mHandler.startQueryEntities(TOKEN_ENTITIES, null, RawContacts.CONTENT_URI,
+ RawContacts.CONTACT_ID + "=" + contactId, null, null);
+ mHandler.startQuery(TOKEN_STATUSES, null, dataUri, StatusQuery.PROJECTION,
+ StatusUpdates.PRESENCE + " IS NOT NULL OR " + StatusUpdates.STATUS
+ + " IS NOT NULL", null, null);
+
+ mContactHeaderWidget.bindFromContactLookupUri(mLookupUri);
+ }
+
+ private void closeCursor() {
+ if (mCursor != null) {
+ mCursor.unregisterContentObserver(mObserver);
+ mCursor.close();
+ mCursor = null;
+ }
+ }
+
+ /**
+ * Consider binding views after any of several background queries has
+ * completed. We check internal flags and only bind when all data has
+ * arrived.
+ */
+ private void considerBindData() {
+ if (mHasEntities && mHasStatuses) {
+ bindData();
+ }
+ }
+
+ private void bindData() {
+
+ // Build up the contact entries
+ buildEntries();
+
+ // Collapse similar data items in select sections.
+ Collapser.collapseList(mPhoneEntries);
+ Collapser.collapseList(mSmsEntries);
+ Collapser.collapseList(mEmailEntries);
+ Collapser.collapseList(mPostalEntries);
+ Collapser.collapseList(mImEntries);
+
+ if (mAdapter == null) {
+ mAdapter = new ViewAdapter(this, mSections);
+ mListView.setAdapter(mAdapter);
+ } else {
+ mAdapter.setSections(mSections, SHOW_SEPARATORS);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, 0, 0, R.string.menu_editContact)
- .setIcon(android.R.drawable.ic_menu_edit)
- .setIntent(new Intent(Intent.ACTION_EDIT, mUri))
- .setAlphabeticShortcut('e');
- menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_deleteContact)
- .setIcon(android.R.drawable.ic_menu_delete);
+ super.onCreateOptionsMenu(menu);
+ final MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.view, menu);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- // Perform this check each time the menu is about to be shown, because the Barcode Scanner
- // could be installed or uninstalled at any time.
- if (isBarcodeScannerInstalled()) {
- if (menu.findItem(MENU_ITEM_SHOW_BARCODE) == null) {
- menu.add(0, MENU_ITEM_SHOW_BARCODE, 0, R.string.menu_showBarcode)
- .setIcon(R.drawable.ic_menu_show_barcode);
- }
- } else {
- menu.removeItem(MENU_ITEM_SHOW_BARCODE);
- }
- return true;
- }
- private boolean isBarcodeScannerInstalled() {
- final Intent intent = new Intent(SHOW_BARCODE_INTENT);
- ResolveInfo ri = getPackageManager().resolveActivity(intent,
- PackageManager.MATCH_DEFAULT_ONLY);
- return ri != null;
+ // Only allow edit when we have at least one raw_contact id
+ final boolean hasRawContact = (mRawContactIds.size() > 0);
+ menu.findItem(R.id.menu_edit).setEnabled(hasRawContact);
+
+ // Only allow share when unrestricted contacts available
+ menu.findItem(R.id.menu_share).setEnabled(!mAllRestricted);
+
+ return true;
}
@Override
@@ -376,105 +476,214 @@
}
ViewEntry entry = ContactEntryAdapter.getEntry(mSections, info.position, SHOW_SEPARATORS);
- switch (entry.kind) {
- case Contacts.KIND_PHONE: {
- menu.add(0, 0, 0, R.string.menu_call).setIntent(entry.intent);
- menu.add(0, 0, 0, R.string.menu_sendSMS).setIntent(entry.auxIntent);
- if (entry.primaryIcon == -1) {
- menu.add(0, MENU_ITEM_MAKE_DEFAULT, 0, R.string.menu_makeDefaultNumber);
- }
- break;
+ menu.setHeaderTitle(R.string.contactOptionsTitle);
+ if (entry.mimetype.equals(CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
+ menu.add(0, 0, 0, R.string.menu_call).setIntent(entry.intent);
+ menu.add(0, 0, 0, R.string.menu_sendSMS).setIntent(entry.secondaryIntent);
+ if (!entry.isPrimary) {
+ menu.add(0, MENU_ITEM_MAKE_DEFAULT, 0, R.string.menu_makeDefaultNumber);
}
-
- case Contacts.KIND_EMAIL: {
- menu.add(0, 0, 0, R.string.menu_sendEmail).setIntent(entry.intent);
- break;
+ } else if (entry.mimetype.equals(CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
+ menu.add(0, 0, 0, R.string.menu_sendEmail).setIntent(entry.intent);
+ if (!entry.isPrimary) {
+ menu.add(0, MENU_ITEM_MAKE_DEFAULT, 0, R.string.menu_makeDefaultEmail);
}
-
- case Contacts.KIND_POSTAL: {
- menu.add(0, 0, 0, R.string.menu_viewAddress).setIntent(entry.intent);
- break;
- }
+ } else if (entry.mimetype.equals(CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)) {
+ menu.add(0, 0, 0, R.string.menu_viewAddress).setIntent(entry.intent);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case MENU_ITEM_DELETE: {
+ case R.id.menu_edit: {
+ Long rawContactIdToEdit = null;
+ if (mRawContactIds.size() > 0) {
+ rawContactIdToEdit = mRawContactIds.get(0);
+ } else {
+ // There is no rawContact to edit.
+ break;
+ }
+ Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
+ rawContactIdToEdit);
+ startActivityForResult(new Intent(Intent.ACTION_EDIT, rawContactUri),
+ REQUEST_EDIT_CONTACT);
+ break;
+ }
+ case R.id.menu_delete: {
// Get confirmation
- showDialog(DIALOG_CONFIRM_DELETE);
+ if (mReadOnlySourcesCnt > 0 & mWritableSourcesCnt > 0) {
+ showDialog(DIALOG_CONFIRM_READONLY_DELETE);
+ } else if (mReadOnlySourcesCnt > 0 && mWritableSourcesCnt == 0) {
+ showDialog(DIALOG_CONFIRM_READONLY_HIDE);
+ } else if (mReadOnlySourcesCnt == 0 && mWritableSourcesCnt > 1) {
+ showDialog(DIALOG_CONFIRM_MULTIPLE_DELETE);
+ } else {
+ showDialog(DIALOG_CONFIRM_DELETE);
+ }
return true;
}
- case MENU_ITEM_SHOW_BARCODE:
- if (mCursor.moveToFirst()) {
- Intent intent = new Intent(SHOW_BARCODE_INTENT);
- intent.putExtra("ENCODE_TYPE", "CONTACT_TYPE");
- Bundle bundle = new Bundle();
- String name = mCursor.getString(CONTACT_NAME_COLUMN);
- if (!TextUtils.isEmpty(name)) {
- // Correctly handle when section headers are hidden
- int sepAdjust = SHOW_SEPARATORS ? 1 : 0;
-
- bundle.putString(Contacts.Intents.Insert.NAME, name);
- // The 0th ViewEntry in each ArrayList below is a separator item
- int entriesToAdd = Math.min(mPhoneEntries.size() - sepAdjust, PHONE_KEYS.length);
- for (int x = 0; x < entriesToAdd; x++) {
- ViewEntry entry = mPhoneEntries.get(x + sepAdjust);
- bundle.putString(PHONE_KEYS[x], entry.data);
- }
- entriesToAdd = Math.min(mEmailEntries.size() - sepAdjust, EMAIL_KEYS.length);
- for (int x = 0; x < entriesToAdd; x++) {
- ViewEntry entry = mEmailEntries.get(x + sepAdjust);
- bundle.putString(EMAIL_KEYS[x], entry.data);
- }
- if (mPostalEntries.size() >= 1 + sepAdjust) {
- ViewEntry entry = mPostalEntries.get(sepAdjust);
- bundle.putString(Contacts.Intents.Insert.POSTAL, entry.data);
- }
- intent.putExtra("ENCODE_DATA", bundle);
- try {
- startActivity(intent);
- } catch (ActivityNotFoundException e) {
- // The check in onPrepareOptionsMenu() should make this impossible, but
- // for safety I'm catching the exception rather than crashing. Ideally
- // I'd call Menu.removeItem() here too, but I don't see a way to get
- // the options menu.
- Log.e(TAG, "Show barcode menu item was clicked but Barcode Scanner " +
- "was not installed.");
- }
- return true;
- }
+ case R.id.menu_join: {
+ showJoinAggregateActivity();
+ return true;
+ }
+ case R.id.menu_options: {
+ showOptionsActivity();
+ return true;
+ }
+ case R.id.menu_share: {
+ if (mAllRestricted) return false;
+
+ // TODO: Keep around actual LOOKUP_KEY, or formalize method of extracting
+ final String lookupKey = mLookupUri.getPathSegments().get(2);
+ final Uri shareUri = Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, lookupKey);
+
+ final Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType(Contacts.CONTENT_VCARD_TYPE);
+ intent.putExtra(Intent.EXTRA_STREAM, shareUri);
+
+ // Launch chooser to share contact via
+ final CharSequence chooseTitle = getText(R.string.share_via);
+ final Intent chooseIntent = Intent.createChooser(intent, chooseTitle);
+
+ try {
+ startActivity(chooseIntent);
+ } catch (ActivityNotFoundException ex) {
+ Toast.makeText(this, R.string.share_error, Toast.LENGTH_SHORT).show();
}
- break;
+ return true;
+ }
}
return super.onOptionsItemSelected(item);
}
-
+
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_MAKE_DEFAULT: {
- AdapterView.AdapterContextMenuInfo info;
- try {
- info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
- } catch (ClassCastException e) {
- Log.e(TAG, "bad menuInfo", e);
- break;
+ if (makeItemDefault(item)) {
+ return true;
}
-
- ViewEntry entry = ContactEntryAdapter.getEntry(mSections, info.position,
- SHOW_SEPARATORS);
- ContentValues values = new ContentValues(1);
- values.put(People.PRIMARY_PHONE_ID, entry.id);
- getContentResolver().update(mUri, values, null, null);
- dataChanged();
- return true;
+ break;
}
}
+
return super.onContextItemSelected(item);
}
+ private boolean makeItemDefault(MenuItem item) {
+ ViewEntry entry = getViewEntryForMenuItem(item);
+ if (entry == null) {
+ return false;
+ }
+
+ // Update the primary values in the data record.
+ ContentValues values = new ContentValues(1);
+ values.put(Data.IS_SUPER_PRIMARY, 1);
+ getContentResolver().update(ContentUris.withAppendedId(Data.CONTENT_URI, entry.id),
+ values, null, null);
+ startEntityQuery();
+ return true;
+ }
+
+ /**
+ * Shows a list of aggregates that can be joined into the currently viewed aggregate.
+ */
+ public void showJoinAggregateActivity() {
+ long freshId = getRefreshedContactId();
+ if (freshId > 0) {
+ String displayName = null;
+ if (mCursor.moveToFirst()) {
+ displayName = mCursor.getString(0);
+ }
+ Intent intent = new Intent(ContactsListActivity.JOIN_AGGREGATE);
+ intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_ID, freshId);
+ if (displayName != null) {
+ intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_NAME, displayName);
+ }
+ startActivityForResult(intent, REQUEST_JOIN_CONTACT);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ if (requestCode == REQUEST_JOIN_CONTACT) {
+ if (resultCode == RESULT_OK && intent != null) {
+ final long contactId = ContentUris.parseId(intent.getData());
+ joinAggregate(contactId);
+ }
+ } else if (requestCode == REQUEST_EDIT_CONTACT) {
+ if (resultCode == EditContactActivity.RESULT_CLOSE_VIEW_ACTIVITY) {
+ finish();
+ } else if (resultCode == Activity.RESULT_OK) {
+ mLookupUri = intent.getData();
+ if (mLookupUri == null) {
+ finish();
+ }
+ }
+ }
+ }
+
+ private void splitContact(long rawContactId) {
+ setAggregationException(rawContactId, AggregationExceptions.TYPE_KEEP_SEPARATE);
+
+ // The split operation may have removed the original aggregate contact, so we need
+ // to requery everything
+ Toast.makeText(this, R.string.contactsSplitMessage, Toast.LENGTH_LONG).show();
+ startEntityQuery();
+ }
+
+ private void joinAggregate(final long contactId) {
+ Cursor c = mResolver.query(RawContacts.CONTENT_URI, new String[] {RawContacts._ID},
+ RawContacts.CONTACT_ID + "=" + contactId, null, null);
+
+ try {
+ while(c.moveToNext()) {
+ long rawContactId = c.getLong(0);
+ setAggregationException(rawContactId, AggregationExceptions.TYPE_KEEP_TOGETHER);
+ }
+ } finally {
+ c.close();
+ }
+
+ Toast.makeText(this, R.string.contactsJoinedMessage, Toast.LENGTH_LONG).show();
+ startEntityQuery();
+ }
+
+ /**
+ * Given a contact ID sets an aggregation exception to either join the contact with the
+ * current aggregate or split off.
+ */
+ protected void setAggregationException(long rawContactId, int exceptionType) {
+ ContentValues values = new ContentValues(3);
+ for (long aRawContactId : mRawContactIds) {
+ if (aRawContactId != rawContactId) {
+ values.put(AggregationExceptions.RAW_CONTACT_ID1, aRawContactId);
+ values.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId);
+ values.put(AggregationExceptions.TYPE, exceptionType);
+ mResolver.update(AggregationExceptions.CONTENT_URI, values, null, null);
+ }
+ }
+ }
+
+ private void showOptionsActivity() {
+ final Intent intent = new Intent(this, ContactOptionsActivity.class);
+ intent.setData(mLookupUri);
+ startActivity(intent);
+ }
+
+ private ViewEntry getViewEntryForMenuItem(MenuItem item) {
+ AdapterView.AdapterContextMenuInfo info;
+ try {
+ info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+ } catch (ClassCastException e) {
+ Log.e(TAG, "bad menuInfo", e);
+ return null;
+ }
+
+ return ContactEntryAdapter.getEntry(mSections, info.position, SHOW_SEPARATORS);
+ }
+
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
@@ -490,23 +699,35 @@
// Fall through and try to call the contact
}
- int index = getListView().getSelectedItemPosition();
+ int index = mListView.getSelectedItemPosition();
if (index != -1) {
ViewEntry entry = ViewAdapter.getEntry(mSections, index, SHOW_SEPARATORS);
- if (entry.kind == Contacts.KIND_PHONE) {
- Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, entry.uri);
- startActivity(intent);
+ if (entry.intent.getAction() == Intent.ACTION_CALL_PRIVILEGED) {
+ startActivity(entry.intent);
}
} else if (mNumPhoneNumbers != 0) {
// There isn't anything selected, call the default number
- Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, mUri);
- startActivity(intent);
+ long freshContactId = getRefreshedContactId();
+ if (freshContactId > 0) {
+ Uri hardContacUri = ContentUris.withAppendedId(
+ Contacts.CONTENT_URI, freshContactId);
+ Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, hardContacUri);
+ startActivity(intent);
+ }
}
return true;
}
case KeyEvent.KEYCODE_DEL: {
- showDialog(DIALOG_CONFIRM_DELETE);
+ if (mReadOnlySourcesCnt > 0 & mWritableSourcesCnt > 0) {
+ showDialog(DIALOG_CONFIRM_READONLY_DELETE);
+ } else if (mReadOnlySourcesCnt > 0 && mWritableSourcesCnt == 0) {
+ showDialog(DIALOG_CONFIRM_READONLY_HIDE);
+ } else if (mReadOnlySourcesCnt == 0 && mWritableSourcesCnt > 1) {
+ showDialog(DIALOG_CONFIRM_MULTIPLE_DELETE);
+ } else {
+ showDialog(DIALOG_CONFIRM_DELETE);
+ }
return true;
}
}
@@ -514,8 +735,7 @@
return super.onKeyDown(keyCode, event);
}
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
+ public void onItemClick(AdapterView parent, View v, int position, long id) {
ViewEntry entry = ViewAdapter.getEntry(mSections, position, SHOW_SEPARATORS);
if (entry != null) {
Intent intent = entry.intent;
@@ -542,413 +762,352 @@
}
/**
- * Build separator entries for all of the sections.
- */
- private void buildSeparators() {
- ViewEntry separator;
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorCallNumber);
- mPhoneEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorSendSmsMms);
- mSmsEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorSendEmail);
- mEmailEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorSendIm);
- mImEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorMapAddress);
- mPostalEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorOrganizations);
- mOrganizationEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorOtherInformation);
- mOtherEntries.add(separator);
- }
-
- private Uri constructImToUrl(String host, String data) {
- // don't encode the url, because the Activity Manager can't find using the encoded url
- StringBuilder buf = new StringBuilder("imto://");
- buf.append(host);
- buf.append('/');
- buf.append(data);
- return Uri.parse(buf.toString());
- }
-
- /**
* Build up the entries to display on the screen.
- *
+ *
* @param personCursor the URI for the contact being displayed
*/
- private final void buildEntries(Cursor personCursor) {
+ private final void buildEntries() {
// Clear out the old entries
final int numSections = mSections.size();
for (int i = 0; i < numSections; i++) {
mSections.get(i).clear();
}
- if (SHOW_SEPARATORS) {
- buildSeparators();
- }
+ mRawContactIds.clear();
- // Build up the phone entries
- final Uri phonesUri = Uri.withAppendedPath(mUri, People.Phones.CONTENT_DIRECTORY);
- final Cursor phonesCursor = mResolver.query(phonesUri, PHONES_PROJECTION, null, null,
- Phones.ISPRIMARY + " DESC");
+ mReadOnlySourcesCnt = 0;
+ mWritableSourcesCnt = 0;
+ mAllRestricted = true;
- if (phonesCursor != null) {
- while (phonesCursor.moveToNext()) {
- final int type = phonesCursor.getInt(PHONES_TYPE_COLUMN);
- final String number = phonesCursor.getString(PHONES_NUMBER_COLUMN);
- final String label = phonesCursor.getString(PHONES_LABEL_COLUMN);
- final boolean isPrimary = phonesCursor.getInt(PHONES_ISPRIMARY_COLUMN) == 1;
- final long id = phonesCursor.getLong(PHONES_ID_COLUMN);
- final Uri uri = ContentUris.withAppendedId(phonesUri, id);
+ mWritableRawContactIds.clear();
- // Don't crash if the number is bogus
- if (TextUtils.isEmpty(number)) {
- Log.w(TAG, "empty number for phone " + id);
- continue;
+ final Context context = this;
+ final Sources sources = Sources.getInstance(context);
+
+ // Build up method entries
+ if (mLookupUri != null) {
+ for (Entity entity: mEntities) {
+ final ContentValues entValues = entity.getEntityValues();
+ final String accountType = entValues.getAsString(RawContacts.ACCOUNT_TYPE);
+ final long rawContactId = entValues.getAsLong(RawContacts._ID);
+
+ // Mark when this contact has any unrestricted components
+ final boolean isRestricted = entValues.getAsInteger(RawContacts.IS_RESTRICTED) != 0;
+ if (!isRestricted) mAllRestricted = false;
+
+ if (!mRawContactIds.contains(rawContactId)) {
+ mRawContactIds.add(rawContactId);
+ }
+ ContactsSource contactsSource = sources.getInflatedSource(accountType,
+ ContactsSource.LEVEL_SUMMARY);
+ if (contactsSource != null && contactsSource.readOnly) {
+ mReadOnlySourcesCnt += 1;
+ } else {
+ mWritableSourcesCnt += 1;
+ mWritableRawContactIds.add(rawContactId);
}
- mNumPhoneNumbers++;
-
- // Add a phone number entry
- final ViewEntry entry = new ViewEntry();
- final CharSequence displayLabel = Phones.getDisplayLabel(this, type, label);
- entry.label = buildActionString(R.string.actionCall, displayLabel, true);
- entry.data = number;
- entry.id = id;
- entry.uri = uri;
- entry.intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, entry.uri);
- entry.auxIntent = new Intent(Intent.ACTION_SENDTO,
- Uri.fromParts("sms", number, null));
- entry.kind = Contacts.KIND_PHONE;
- if (isPrimary) {
- entry.primaryIcon = R.drawable.ic_default_number;
- }
- entry.actionIcon = android.R.drawable.sym_action_call;
- mPhoneEntries.add(entry);
- if (type == Phones.TYPE_MOBILE || mShowSmsLinksForAllPhones) {
- // Add an SMS entry
- ViewEntry smsEntry = new ViewEntry();
- smsEntry.label = buildActionString(R.string.actionText, displayLabel, true);
- smsEntry.data = number;
- smsEntry.id = id;
- smsEntry.uri = uri;
- smsEntry.intent = entry.auxIntent;
- smsEntry.kind = ViewEntry.KIND_SMS;
- smsEntry.actionIcon = R.drawable.sym_action_sms;
- mSmsEntries.add(smsEntry);
- }
- }
+ for (NamedContentValues subValue : entity.getSubValues()) {
+ final ContentValues entryValues = subValue.values;
+ entryValues.put(Data.RAW_CONTACT_ID, rawContactId);
- phonesCursor.close();
- }
+ final long dataId = entryValues.getAsLong(Data._ID);
+ final String mimeType = entryValues.getAsString(Data.MIMETYPE);
+ if (mimeType == null) continue;
- // Build the contact method entries
- final Uri methodsUri = Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY);
- Cursor methodsCursor = mResolver.query(
- Uri.withAppendedPath(mUri, "contact_methods_with_presence"),
- METHODS_WITH_PRESENCE_PROJECTION, null, null, null);
+ final DataKind kind = sources.getKindOrFallback(accountType, mimeType, this,
+ ContactsSource.LEVEL_MIMETYPES);
+ if (kind == null) continue;
- if (methodsCursor != null) {
- String[] protocolStrings = getResources().getStringArray(android.R.array.imProtocols);
+ final ViewEntry entry = ViewEntry.fromValues(context, mimeType, kind,
+ rawContactId, dataId, entryValues);
- while (methodsCursor.moveToNext()) {
- final int kind = methodsCursor.getInt(METHODS_KIND_COLUMN);
- final String label = methodsCursor.getString(METHODS_LABEL_COLUMN);
- final String data = methodsCursor.getString(METHODS_DATA_COLUMN);
- final int type = methodsCursor.getInt(METHODS_TYPE_COLUMN);
- final long id = methodsCursor.getLong(METHODS_ID_COLUMN);
- final Uri uri = ContentUris.withAppendedId(methodsUri, id);
+ final boolean hasData = !TextUtils.isEmpty(entry.data);
+ final boolean isSuperPrimary = entryValues.getAsInteger(
+ Data.IS_SUPER_PRIMARY) != 0;
- // Don't crash if the data is bogus
- if (TextUtils.isEmpty(data)) {
- Log.w(TAG, "empty data for contact method " + id);
- continue;
- }
+ if (Phone.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ // Build phone entries
+ mNumPhoneNumbers++;
- ViewEntry entry = new ViewEntry();
- entry.id = id;
- entry.uri = uri;
- entry.kind = kind;
+ entry.intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
+ Uri.fromParts(Constants.SCHEME_TEL, entry.data, null));
+ entry.secondaryIntent = new Intent(Intent.ACTION_SENDTO,
+ Uri.fromParts(Constants.SCHEME_SMSTO, entry.data, null));
- switch (kind) {
- case Contacts.KIND_EMAIL:
- entry.label = buildActionString(R.string.actionEmail,
- ContactMethods.getDisplayLabel(this, kind, type, label), true);
- entry.data = data;
- entry.intent = new Intent(Intent.ACTION_SENDTO,
- Uri.fromParts("mailto", data, null));
- entry.actionIcon = android.R.drawable.sym_action_email;
- mEmailEntries.add(entry);
- break;
+ entry.isPrimary = isSuperPrimary;
+ mPhoneEntries.add(entry);
- case Contacts.KIND_POSTAL:
- entry.label = buildActionString(R.string.actionMap,
- ContactMethods.getDisplayLabel(this, kind, type, label), true);
- entry.data = data;
- entry.maxLines = 4;
- entry.intent = new Intent(Intent.ACTION_VIEW, uri);
- entry.actionIcon = R.drawable.sym_action_map;
- mPostalEntries.add(entry);
- break;
-
- case Contacts.KIND_IM: {
- Object protocolObj = ContactMethods.decodeImProtocol(
- methodsCursor.getString(METHODS_AUX_DATA_COLUMN));
- String host;
- if (protocolObj instanceof Number) {
- int protocol = ((Number) protocolObj).intValue();
- entry.label = buildActionString(R.string.actionChat,
- protocolStrings[protocol], false);
- host = ContactMethods.lookupProviderNameFromId(protocol).toLowerCase();
- if (protocol == ContactMethods.PROTOCOL_GOOGLE_TALK
- || protocol == ContactMethods.PROTOCOL_MSN) {
- entry.maxLabelLines = 2;
+ if (entry.type == CommonDataKinds.Phone.TYPE_MOBILE
+ || mShowSmsLinksForAllPhones) {
+ // Add an SMS entry
+ if (kind.iconAltRes > 0) {
+ entry.secondaryActionIcon = kind.iconAltRes;
}
- } else {
- String providerName = (String) protocolObj;
- entry.label = buildActionString(R.string.actionChat,
- providerName, false);
- host = providerName.toLowerCase();
+ }
+ } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ // Build email entries
+ entry.intent = new Intent(Intent.ACTION_SENDTO,
+ Uri.fromParts(Constants.SCHEME_MAILTO, entry.data, null));
+ entry.isPrimary = isSuperPrimary;
+ mEmailEntries.add(entry);
+
+ // When Email rows have status, create additional Im row
+ final DataStatus status = mStatuses.get(entry.id);
+ if (status != null) {
+ final String imMime = Im.CONTENT_ITEM_TYPE;
+ final DataKind imKind = sources.getKindOrFallback(accountType,
+ imMime, this, ContactsSource.LEVEL_MIMETYPES);
+ final ViewEntry imEntry = ViewEntry.fromValues(context,
+ imMime, imKind, rawContactId, dataId, entryValues);
+ imEntry.intent = ContactsUtils.buildImIntent(entryValues);
+ imEntry.applyStatus(status, false);
+ mImEntries.add(imEntry);
+ }
+ } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ // Build postal entries
+ entry.maxLines = 4;
+ entry.intent = new Intent(Intent.ACTION_VIEW, entry.uri);
+ mPostalEntries.add(entry);
+ } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ // Build IM entries
+ entry.intent = ContactsUtils.buildImIntent(entryValues);
+ if (TextUtils.isEmpty(entry.label)) {
+ entry.label = getString(R.string.chat).toLowerCase();
}
- // Only add the intent if there is a valid host
- if (!TextUtils.isEmpty(host)) {
- entry.intent = new Intent(Intent.ACTION_SENDTO,
- constructImToUrl(host, data));
+ // Apply presence and status details when available
+ final DataStatus status = mStatuses.get(entry.id);
+ if (status != null) {
+ entry.applyStatus(status, false);
}
- entry.data = data;
- if (!methodsCursor.isNull(METHODS_STATUS_COLUMN)) {
- entry.presenceIcon = Presence.getPresenceIconResourceId(
- methodsCursor.getInt(METHODS_STATUS_COLUMN));
- }
- entry.actionIcon = android.R.drawable.sym_action_chat;
mImEntries.add(entry);
- break;
- }
- }
- }
-
- methodsCursor.close();
- }
-
- // Build IM entries for things we have presence info about but not explicit IM entries for
- long personId = ContentUris.parseId(mUri);
- String[] projection = new String[] {
- Presence.IM_HANDLE, // 0
- Presence.IM_PROTOCOL, // 1
- Presence.PRESENCE_STATUS, // 2
- };
- Cursor presenceCursor = mResolver.query(Presence.CONTENT_URI, projection,
- Presence.PERSON_ID + "=" + personId, null, null);
- if (presenceCursor != null) {
- try {
- while (presenceCursor.moveToNext()) {
- // Find the display info for the provider
- String data = presenceCursor.getString(0);
- String label;
- Object protocolObj = ContactMethods.decodeImProtocol(
- presenceCursor.getString(1));
- String host;
- if (protocolObj instanceof Number) {
- int protocol = ((Number) protocolObj).intValue();
- label = getResources().getStringArray(
- android.R.array.imProtocols)[protocol];
- host = ContactMethods.lookupProviderNameFromId(protocol).toLowerCase();
+ } else if ((Organization.CONTENT_ITEM_TYPE.equals(mimeType)
+ || Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) && hasData) {
+ // Build organization and note entries
+ entry.uri = null;
+ mOrganizationEntries.add(entry);
+ } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ // Build note entries
+ entry.uri = null;
+ entry.maxLines = 10;
+ mOtherEntries.add(entry);
} else {
- String providerName = (String) protocolObj;
- label = providerName;
- host = providerName.toLowerCase();
- }
+ // Handle showing custom rows
+ entry.intent = new Intent(Intent.ACTION_VIEW, entry.uri);
- if (TextUtils.isEmpty(host)) {
- // A valid provider name is required
- continue;
- }
+ // Use social summary when requested by external source
+ final DataStatus status = mStatuses.get(entry.id);
+ final boolean hasSocial = kind.actionBodySocial && status != null;
+ if (hasSocial) {
+ entry.applyStatus(status, true);
+ }
-
- Intent intent = new Intent(Intent.ACTION_SENDTO, constructImToUrl(host, data));
-
- // Check to see if there is already an entry for this IM account
- boolean addEntry = true;
- int numImEntries = mImEntries.size();
- for (int i = 0; i < numImEntries; i++) {
- // Check to see if the intent point to the same thing, if so we won't
- // add this entry to the list since there is already an explict entry
- // for the IM account
- Intent existingIntent = mImEntries.get(i).intent;
- if (intent.filterEquals(existingIntent)) {
- addEntry = false;
- break;
+ if (hasSocial || hasData) {
+ mOtherEntries.add(entry);
}
}
-
- // Add the entry if an existing one wasn't found
- if (addEntry) {
- ViewEntry entry = new ViewEntry();
- entry.kind = Contacts.KIND_IM;
- entry.data = data;
- entry.label = label;
- entry.intent = intent;
- entry.actionIcon = android.R.drawable.sym_action_chat;
- entry.presenceIcon = Presence.getPresenceIconResourceId(
- presenceCursor.getInt(2));
- entry.maxLabelLines = 2;
- mImEntries.add(entry);
- }
- }
- } finally {
- presenceCursor.close();
- }
- }
-
- // Build the organization entries
- final Uri organizationsUri = Uri.withAppendedPath(mUri, Organizations.CONTENT_DIRECTORY);
- Cursor organizationsCursor = mResolver.query(organizationsUri, ORGANIZATIONS_PROJECTION,
- null, null, null);
-
- if (organizationsCursor != null) {
- while (organizationsCursor.moveToNext()) {
- ViewEntry entry = new ViewEntry();
- entry.id = organizationsCursor.getLong(ORGANIZATIONS_ID_COLUMN);
- entry.uri = ContentUris.withAppendedId(organizationsUri, entry.id);
- entry.kind = Contacts.KIND_ORGANIZATION;
- entry.label = organizationsCursor.getString(ORGANIZATIONS_COMPANY_COLUMN);
- entry.data = organizationsCursor.getString(ORGANIZATIONS_TITLE_COLUMN);
- entry.actionIcon = R.drawable.sym_action_organization;
-/*
- entry.label = Organizations.getDisplayLabel(this,
- organizationsCursor.getInt(ORGANIZATIONS_TYPE_COLUMN),
- organizationsCursor.getString(ORGANIZATIONS_LABEL_COLUMN)).toString();
-*/
- mOrganizationEntries.add(entry);
- }
-
- organizationsCursor.close();
- }
-
-
- // Build the other entries
- String note = personCursor.getString(CONTACT_NOTES_COLUMN);
- if (!TextUtils.isEmpty(note)) {
- ViewEntry entry = new ViewEntry();
- entry.label = getString(R.string.label_notes);
- entry.data = note;
- entry.id = 0;
- entry.kind = ViewEntry.KIND_CONTACT;
- entry.uri = null;
- entry.intent = null;
- entry.maxLines = 10;
- entry.actionIcon = R.drawable.sym_note;
- mOtherEntries.add(entry);
- }
-
- // Build the ringtone entry
- String ringtoneStr = personCursor.getString(CONTACT_CUSTOM_RINGTONE_COLUMN);
- if (!TextUtils.isEmpty(ringtoneStr)) {
- // Get the URI
- Uri ringtoneUri = Uri.parse(ringtoneStr);
- if (ringtoneUri != null) {
- Ringtone ringtone = RingtoneManager.getRingtone(this, ringtoneUri);
- if (ringtone != null) {
- ViewEntry entry = new ViewEntry();
- entry.label = getString(R.string.label_ringtone);
- entry.data = ringtone.getTitle(this);
- entry.kind = ViewEntry.KIND_CONTACT;
- entry.uri = ringtoneUri;
- entry.actionIcon = R.drawable.sym_ringtone;
- mOtherEntries.add(entry);
}
}
}
-
- // Build the send directly to voice mail entry
- boolean sendToVoicemail = personCursor.getInt(CONTACT_SEND_TO_VOICEMAIL_COLUMN) == 1;
- if (sendToVoicemail) {
- ViewEntry entry = new ViewEntry();
- entry.label = getString(R.string.actionIncomingCall);
- entry.data = getString(R.string.detailIncomingCallsGoToVoicemail);
- entry.kind = ViewEntry.KIND_CONTACT;
- entry.actionIcon = R.drawable.sym_send_to_voicemail;
- mOtherEntries.add(entry);
- }
}
- String buildActionString(int actionResId, CharSequence type, boolean lowerCase) {
- // If there is no type just display an empty string
- if (type == null) {
- type = "";
+ static String buildActionString(DataKind kind, ContentValues values, boolean lowerCase,
+ Context context) {
+ if (kind.actionHeader == null) {
+ return null;
}
-
- if (lowerCase) {
- return getString(actionResId, type.toString().toLowerCase());
- } else {
- return getString(actionResId, type.toString());
+ CharSequence actionHeader = kind.actionHeader.inflateUsing(context, values);
+ if (actionHeader == null) {
+ return null;
}
+ return lowerCase ? actionHeader.toString().toLowerCase() : actionHeader.toString();
}
-
+
+ static String buildDataString(DataKind kind, ContentValues values, Context context) {
+ if (kind.actionBody == null) {
+ return null;
+ }
+ CharSequence actionBody = kind.actionBody.inflateUsing(context, values);
+ return actionBody == null ? null : actionBody.toString();
+ }
+
/**
* A basic structure with the data for a contact entry in the list.
*/
- final static class ViewEntry extends ContactEntryAdapter.Entry {
- public int primaryIcon = -1;
- public Intent intent;
- public Intent auxIntent = null;
- public int presenceIcon = -1;
+ static class ViewEntry extends ContactEntryAdapter.Entry implements Collapsible<ViewEntry> {
+ public Context context = null;
+ public String resPackageName = null;
public int actionIcon = -1;
+ public boolean isPrimary = false;
+ public int secondaryActionIcon = -1;
+ public Intent intent;
+ public Intent secondaryIntent = null;
public int maxLabelLines = 1;
+ public ArrayList<Long> ids = new ArrayList<Long>();
+ public int collapseCount = 0;
+
+ public int presence = -1;
+ public int presenceIcon = -1;
+
+ public CharSequence footerLine = null;
+
+ private ViewEntry() {
+ }
+
+ /**
+ * Build new {@link ViewEntry} and populate from the given values.
+ */
+ public static ViewEntry fromValues(Context context, String mimeType, DataKind kind,
+ long rawContactId, long dataId, ContentValues values) {
+ final ViewEntry entry = new ViewEntry();
+ entry.context = context;
+ entry.contactId = rawContactId;
+ entry.id = dataId;
+ entry.uri = ContentUris.withAppendedId(Data.CONTENT_URI, entry.id);
+ entry.mimetype = mimeType;
+ entry.label = buildActionString(kind, values, false, context);
+ entry.data = buildDataString(kind, values, context);
+
+ if (kind.typeColumn != null && values.containsKey(kind.typeColumn)) {
+ entry.type = values.getAsInteger(kind.typeColumn);
+ }
+ if (kind.iconRes > 0) {
+ entry.resPackageName = kind.resPackageName;
+ entry.actionIcon = kind.iconRes;
+ }
+
+ return entry;
+ }
+
+ /**
+ * Apply given {@link DataStatus} values over this {@link ViewEntry}
+ *
+ * @param fillData When true, the given status replaces {@link #data}
+ * and {@link #footerLine}. Otherwise only {@link #presence}
+ * is updated.
+ */
+ public ViewEntry applyStatus(DataStatus status, boolean fillData) {
+ presence = status.getPresence();
+ presenceIcon = (presence == -1) ? -1 :
+ StatusUpdates.getPresenceIconResourceId(this.presence);
+
+ if (fillData && status.isValid()) {
+ this.data = status.getStatus().toString();
+ this.footerLine = status.getTimestampLabel(context);
+ }
+
+ return this;
+ }
+
+ public boolean collapseWith(ViewEntry entry) {
+ // assert equal collapse keys
+ if (!shouldCollapseWith(entry)) {
+ return false;
+ }
+
+ // Choose the label associated with the highest type precedence.
+ if (TypePrecedence.getTypePrecedence(mimetype, type)
+ > TypePrecedence.getTypePrecedence(entry.mimetype, entry.type)) {
+ type = entry.type;
+ label = entry.label;
+ }
+
+ // Choose the max of the maxLines and maxLabelLines values.
+ maxLines = Math.max(maxLines, entry.maxLines);
+ maxLabelLines = Math.max(maxLabelLines, entry.maxLabelLines);
+
+ // Choose the presence with the highest precedence.
+ if (StatusUpdates.getPresencePrecedence(presence)
+ < StatusUpdates.getPresencePrecedence(entry.presence)) {
+ presence = entry.presence;
+ }
+
+ // If any of the collapsed entries are primary make the whole thing primary.
+ isPrimary = entry.isPrimary ? true : isPrimary;
+
+ // uri, and contactdId, shouldn't make a difference. Just keep the original.
+
+ // Keep track of all the ids that have been collapsed with this one.
+ ids.add(entry.id);
+ collapseCount++;
+ return true;
+ }
+
+ public boolean shouldCollapseWith(ViewEntry entry) {
+ if (entry == null) {
+ return false;
+ }
+
+ if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)
+ && Phone.CONTENT_ITEM_TYPE.equals(entry.mimetype)) {
+ if (!PhoneNumberUtils.compare(this.context, data, entry.data)) {
+ return false;
+ }
+ } else {
+ if (!equals(data, entry.data)) {
+ return false;
+ }
+ }
+
+ if (!equals(mimetype, entry.mimetype)
+ || !intentCollapsible(intent, entry.intent)
+ || !intentCollapsible(secondaryIntent, entry.secondaryIntent)
+ || actionIcon != entry.actionIcon) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean equals(Object a, Object b) {
+ return a==b || (a != null && a.equals(b));
+ }
+
+ private boolean intentCollapsible(Intent a, Intent b) {
+ if (a == b) {
+ return true;
+ } else if ((a != null && b != null) && equals(a.getAction(), b.getAction())) {
+ return true;
+ }
+ return false;
+ }
}
- private static final class ViewAdapter extends ContactEntryAdapter<ViewEntry> {
- /** Cache of the children views of a row */
- static class ViewCache {
- public TextView label;
- public TextView data;
- public ImageView actionIcon;
- public ImageView presenceIcon;
-
- // Need to keep track of this too
- ViewEntry entry;
- }
-
+ /** Cache of the children views of a row */
+ static class ViewCache {
+ public TextView label;
+ public TextView data;
+ public TextView footer;
+ public ImageView actionIcon;
+ public ImageView presenceIcon;
+ public ImageView primaryIcon;
+ public ImageView secondaryActionButton;
+ public View secondaryActionDivider;
+
+ // Need to keep track of this too
+ ViewEntry entry;
+ }
+
+ private final class ViewAdapter extends ContactEntryAdapter<ViewEntry>
+ implements View.OnClickListener {
+
+
ViewAdapter(Context context, ArrayList<ArrayList<ViewEntry>> sections) {
super(context, sections, SHOW_SEPARATORS);
}
+ public void onClick(View v) {
+ Intent intent = (Intent) v.getTag();
+ startActivity(intent);
+ }
+
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- ViewEntry entry = getEntry(mSections, position, false);
+ ViewEntry entry = getEntry(mSections, position, false);
View v;
- // Handle separators specially
- if (entry.kind == ViewEntry.KIND_SEPARATOR) {
- TextView separator = (TextView) mInflater.inflate(
- R.layout.list_separator, parent, SHOW_SEPARATORS);
- separator.setText(entry.data);
- return separator;
- }
-
ViewCache views;
// Check to see if we can reuse convertView
@@ -963,8 +1122,14 @@
views = new ViewCache();
views.label = (TextView) v.findViewById(android.R.id.text1);
views.data = (TextView) v.findViewById(android.R.id.text2);
- views.actionIcon = (ImageView) v.findViewById(R.id.icon1);
- views.presenceIcon = (ImageView) v.findViewById(R.id.icon2);
+ views.footer = (TextView) v.findViewById(R.id.footer);
+ views.actionIcon = (ImageView) v.findViewById(R.id.action_icon);
+ views.primaryIcon = (ImageView) v.findViewById(R.id.primary_icon);
+ views.presenceIcon = (ImageView) v.findViewById(R.id.presence_icon);
+ views.secondaryActionButton = (ImageView) v.findViewById(
+ R.id.secondary_action_button);
+ views.secondaryActionButton.setOnClickListener(this);
+ views.secondaryActionDivider = v.findViewById(R.id.divider);
v.setTag(views);
}
@@ -995,14 +1160,38 @@
// Set the data
TextView data = views.data;
if (data != null) {
- data.setText(entry.data);
+ if (entry.mimetype.equals(Phone.CONTENT_ITEM_TYPE)
+ || entry.mimetype.equals(Constants.MIME_SMS_ADDRESS)) {
+ data.setText(PhoneNumberUtils.formatNumber(entry.data));
+ } else {
+ data.setText(entry.data);
+ }
setMaxLines(data, entry.maxLines);
}
+ // Set the footer
+ if (!TextUtils.isEmpty(entry.footerLine)) {
+ views.footer.setText(entry.footerLine);
+ views.footer.setVisibility(View.VISIBLE);
+ } else {
+ views.footer.setVisibility(View.GONE);
+ }
+
+ // Set the primary icon
+ views.primaryIcon.setVisibility(entry.isPrimary ? View.VISIBLE : View.GONE);
+
// Set the action icon
ImageView action = views.actionIcon;
if (entry.actionIcon != -1) {
- action.setImageDrawable(resources.getDrawable(entry.actionIcon));
+ Drawable actionIcon;
+ if (entry.resPackageName != null) {
+ // Load external resources through PackageManager
+ actionIcon = mContext.getPackageManager().getDrawable(entry.resPackageName,
+ entry.actionIcon, null);
+ } else {
+ actionIcon = resources.getDrawable(entry.actionIcon);
+ }
+ action.setImageDrawable(actionIcon);
action.setVisibility(View.VISIBLE);
} else {
// Things should still line up as if there was an icon, so make it invisible
@@ -1011,18 +1200,34 @@
// Set the presence icon
Drawable presenceIcon = null;
- if (entry.primaryIcon != -1) {
- presenceIcon = resources.getDrawable(entry.primaryIcon);
- } else if (entry.presenceIcon != -1) {
+ if (entry.presenceIcon != -1) {
presenceIcon = resources.getDrawable(entry.presenceIcon);
+ } else if (entry.presence != -1) {
+ presenceIcon = resources.getDrawable(
+ StatusUpdates.getPresenceIconResourceId(entry.presence));
+ }
+ ImageView presenceIconView = views.presenceIcon;
+ if (presenceIcon != null) {
+ presenceIconView.setImageDrawable(presenceIcon);
+ presenceIconView.setVisibility(View.VISIBLE);
+ } else {
+ presenceIconView.setVisibility(View.GONE);
}
- ImageView presence = views.presenceIcon;
- if (presenceIcon != null) {
- presence.setImageDrawable(presenceIcon);
- presence.setVisibility(View.VISIBLE);
+ // Set the secondary action button
+ ImageView secondaryActionView = views.secondaryActionButton;
+ Drawable secondaryActionIcon = null;
+ if (entry.secondaryActionIcon != -1) {
+ secondaryActionIcon = resources.getDrawable(entry.secondaryActionIcon);
+ }
+ if (entry.secondaryIntent != null && secondaryActionIcon != null) {
+ secondaryActionView.setImageDrawable(secondaryActionIcon);
+ secondaryActionView.setTag(entry.secondaryIntent);
+ secondaryActionView.setVisibility(View.VISIBLE);
+ views.secondaryActionDivider.setVisibility(View.VISIBLE);
} else {
- presence.setVisibility(View.GONE);
+ secondaryActionView.setVisibility(View.GONE);
+ views.secondaryActionDivider.setVisibility(View.GONE);
}
}
@@ -1037,4 +1242,18 @@
}
}
}
+
+ private interface StatusQuery {
+ final String[] PROJECTION = new String[] {
+ Data._ID,
+ Data.STATUS,
+ Data.STATUS_RES_PACKAGE,
+ Data.STATUS_ICON,
+ Data.STATUS_LABEL,
+ Data.STATUS_TIMESTAMP,
+ Data.PRESENCE,
+ };
+
+ final int _ID = 0;
+ }
}
diff --git a/src/com/android/contacts/model/ContactsSource.java b/src/com/android/contacts/model/ContactsSource.java
new file mode 100644
index 0000000..1198837
--- /dev/null
+++ b/src/com/android/contacts/model/ContactsSource.java
@@ -0,0 +1,316 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import android.accounts.Account;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.widget.EditText;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Internal structure that represents constraints and styles for a specific data
+ * source, such as the various data types they support, including details on how
+ * those types should be rendered and edited.
+ * <p>
+ * In the future this may be inflated from XML defined by a data source.
+ */
+public abstract class ContactsSource {
+ /**
+ * The {@link RawContacts#ACCOUNT_TYPE} these constraints apply to.
+ */
+ public String accountType = null;
+
+ /**
+ * Package that resources should be loaded from, either defined through an
+ * {@link Account} or for matching against {@link Data#RES_PACKAGE}.
+ */
+ public String resPackageName;
+ public String summaryResPackageName;
+
+ public int titleRes;
+ public int iconRes;
+
+ public boolean readOnly;
+
+ /**
+ * Set of {@link DataKind} supported by this source.
+ */
+ private ArrayList<DataKind> mKinds = Lists.newArrayList();
+
+ /**
+ * Lookup map of {@link #mKinds} on {@link DataKind#mimeType}.
+ */
+ private HashMap<String, DataKind> mMimeKinds = Maps.newHashMap();
+
+ public static final int LEVEL_NONE = 0;
+ public static final int LEVEL_SUMMARY = 1;
+ public static final int LEVEL_MIMETYPES = 2;
+ public static final int LEVEL_CONSTRAINTS = 3;
+
+ private int mInflatedLevel = LEVEL_NONE;
+
+ public synchronized boolean isInflated(int inflateLevel) {
+ return mInflatedLevel >= inflateLevel;
+ }
+
+ /** @hide exposed for unit tests */
+ public void setInflatedLevel(int inflateLevel) {
+ mInflatedLevel = inflateLevel;
+ }
+
+ /**
+ * Ensure that this {@link ContactsSource} has been inflated to the
+ * requested level.
+ */
+ public synchronized void ensureInflated(Context context, int inflateLevel) {
+ if (!isInflated(inflateLevel)) {
+ inflate(context, inflateLevel);
+ }
+ }
+
+ /**
+ * Perform the actual inflation to the requested level. Called by
+ * {@link #ensureInflated(Context, int)} when inflation is needed.
+ */
+ protected abstract void inflate(Context context, int inflateLevel);
+
+ /**
+ * Invalidate any cache for this {@link ContactsSource}, removing all
+ * inflated data. Calling {@link #ensureInflated(Context, int)} will
+ * populate again from scratch.
+ */
+ public synchronized void invalidateCache() {
+ this.mKinds.clear();
+ this.mMimeKinds.clear();
+ setInflatedLevel(LEVEL_NONE);
+ }
+
+ public CharSequence getDisplayLabel(Context context) {
+ if (this.titleRes != -1 && this.summaryResPackageName != null) {
+ final PackageManager pm = context.getPackageManager();
+ return pm.getText(this.summaryResPackageName, this.titleRes, null);
+ } else if (this.titleRes != -1) {
+ return context.getText(this.titleRes);
+ } else {
+ return this.accountType;
+ }
+ }
+
+ public Drawable getDisplayIcon(Context context) {
+ if (this.titleRes != -1 && this.summaryResPackageName != null) {
+ final PackageManager pm = context.getPackageManager();
+ return pm.getDrawable(this.summaryResPackageName, this.iconRes, null);
+ } else if (this.titleRes != -1) {
+ return context.getResources().getDrawable(this.iconRes);
+ } else {
+ return null;
+ }
+ }
+
+ abstract public int getHeaderColor(Context context);
+
+ abstract public int getSideBarColor(Context context);
+
+ /**
+ * {@link Comparator} to sort by {@link DataKind#weight}.
+ */
+ private static Comparator<DataKind> sWeightComparator = new Comparator<DataKind>() {
+ public int compare(DataKind object1, DataKind object2) {
+ return object1.weight - object2.weight;
+ }
+ };
+
+ /**
+ * Return list of {@link DataKind} supported, sorted by
+ * {@link DataKind#weight}.
+ */
+ public ArrayList<DataKind> getSortedDataKinds() {
+ // TODO: optimize by marking if already sorted
+ Collections.sort(mKinds, sWeightComparator);
+ return mKinds;
+ }
+
+ /**
+ * Find the {@link DataKind} for a specific MIME-type, if it's handled by
+ * this data source. If you may need a fallback {@link DataKind}, use
+ * {@link Sources#getKindOrFallback(String, String, Context, int)}.
+ */
+ public DataKind getKindForMimetype(String mimeType) {
+ return this.mMimeKinds.get(mimeType);
+ }
+
+ /**
+ * Add given {@link DataKind} to list of those provided by this source.
+ */
+ public DataKind addKind(DataKind kind) {
+ kind.resPackageName = this.resPackageName;
+ this.mKinds.add(kind);
+ this.mMimeKinds.put(kind.mimeType, kind);
+ return kind;
+ }
+
+ /**
+ * Description of a specific data type, usually marked by a unique
+ * {@link Data#MIMETYPE}. Includes details about how to view and edit
+ * {@link Data} rows of this kind, including the possible {@link EditType}
+ * labels and editable {@link EditField}.
+ */
+ public static class DataKind {
+ public String resPackageName;
+ public String mimeType;
+ public int titleRes;
+ public int iconRes;
+ public int iconAltRes;
+ public int weight;
+ public boolean secondary;
+ public boolean editable;
+
+ public StringInflater actionHeader;
+ public StringInflater actionAltHeader;
+ public StringInflater actionBody;
+
+ public boolean actionBodySocial = false;
+
+ public String typeColumn;
+ public int typeOverallMax;
+
+ public List<EditType> typeList;
+ public List<EditField> fieldList;
+
+ public ContentValues defaultValues;
+
+ public DataKind() {
+ }
+
+ public DataKind(String mimeType, int titleRes, int iconRes, int weight, boolean editable) {
+ this.mimeType = mimeType;
+ this.titleRes = titleRes;
+ this.iconRes = iconRes;
+ this.weight = weight;
+ this.editable = editable;
+ this.typeOverallMax = -1;
+ }
+ }
+
+ /**
+ * Description of a specific "type" or "label" of a {@link DataKind} row,
+ * such as {@link Phone#TYPE_WORK}. Includes constraints on total number of
+ * rows a {@link Contacts} may have of this type, and details on how
+ * user-defined labels are stored.
+ */
+ public static class EditType {
+ public int rawValue;
+ public int labelRes;
+// public int actionRes;
+// public int actionAltRes;
+ public boolean secondary;
+ public int specificMax;
+ public String customColumn;
+
+ public EditType(int rawValue, int labelRes) {
+ this.rawValue = rawValue;
+ this.labelRes = labelRes;
+ this.specificMax = -1;
+ }
+
+ public EditType setSecondary(boolean secondary) {
+ this.secondary = secondary;
+ return this;
+ }
+
+ public EditType setSpecificMax(int specificMax) {
+ this.specificMax = specificMax;
+ return this;
+ }
+
+ public EditType setCustomColumn(String customColumn) {
+ this.customColumn = customColumn;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof EditType) {
+ final EditType other = (EditType)object;
+ return other.rawValue == rawValue;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return rawValue;
+ }
+ }
+
+ /**
+ * Description of a user-editable field on a {@link DataKind} row, such as
+ * {@link Phone#NUMBER}. Includes flags to apply to an {@link EditText}, and
+ * the column where this field is stored.
+ */
+ public static class EditField {
+ public String column;
+ public int titleRes;
+ public int inputType;
+ public int minLines;
+ public boolean optional;
+
+ public EditField(String column, int titleRes) {
+ this.column = column;
+ this.titleRes = titleRes;
+ }
+
+ public EditField(String column, int titleRes, int inputType) {
+ this(column, titleRes);
+ this.inputType = inputType;
+ }
+
+ public EditField setOptional(boolean optional) {
+ this.optional = optional;
+ return this;
+ }
+ }
+
+ /**
+ * Generic method of inflating a given {@link Cursor} into a user-readable
+ * {@link CharSequence}. For example, an inflater could combine the multiple
+ * columns of {@link StructuredPostal} together using a string resource
+ * before presenting to the user.
+ */
+ public interface StringInflater {
+ public CharSequence inflateUsing(Context context, Cursor cursor);
+ public CharSequence inflateUsing(Context context, ContentValues values);
+ }
+
+}
diff --git a/src/com/android/contacts/model/Editor.java b/src/com/android/contacts/model/Editor.java
new file mode 100644
index 0000000..b3e8443
--- /dev/null
+++ b/src/com/android/contacts/model/Editor.java
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+
+import android.provider.ContactsContract.Data;
+
+/**
+ * Generic definition of something that edits a {@link Data} row through an
+ * {@link ValuesDelta} object.
+ */
+public interface Editor {
+ /**
+ * Listener for an {@link Editor}, usually to handle deleted items.
+ */
+ public interface EditorListener {
+ /**
+ * Called when the given {@link Editor} has been deleted.
+ */
+ public void onDeleted(Editor editor);
+
+ /**
+ * Called when the given {@link Editor} has a request, for example it
+ * wants to select a photo.
+ */
+ public void onRequest(int request);
+
+ public static final int REQUEST_PICK_PHOTO = 1;
+ public static final int FIELD_CHANGED = 2;
+ }
+
+ /**
+ * Prepare this editor for the given {@link ValuesDelta}, which
+ * builds any needed views. Any changes performed by the user will be
+ * written back to that same object.
+ */
+ public void setValues(DataKind kind, ValuesDelta values, EntityDelta state, boolean readOnly);
+
+ /**
+ * Add a specific {@link EditorListener} to this {@link Editor}.
+ */
+ public void setEditorListener(EditorListener listener);
+
+ /**
+ * Called internally when the contents of a specific field have changed,
+ * allowing advanced editors to persist data in a specific way.
+ */
+ public void onFieldChanged(String column, String value);
+}
diff --git a/src/com/android/contacts/model/EntityDelta.java b/src/com/android/contacts/model/EntityDelta.java
new file mode 100644
index 0000000..ae30806
--- /dev/null
+++ b/src/com/android/contacts/model/EntityDelta.java
@@ -0,0 +1,838 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+import com.google.android.collect.Sets;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.content.Entity;
+import android.content.ContentProviderOperation.Builder;
+import android.content.Entity.NamedContentValues;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.BaseColumns;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.util.Log;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Contains an {@link Entity} and records any modifications separately so the
+ * original {@link Entity} can be swapped out with a newer version and the
+ * changes still cleanly applied.
+ * <p>
+ * One benefit of this approach is that we can build changes entirely on an
+ * empty {@link Entity}, which then becomes an insert {@link RawContacts} case.
+ * <p>
+ * When applying modifications over an {@link Entity}, we try finding the
+ * original {@link Data#_ID} rows where the modifications took place. If those
+ * rows are missing from the new {@link Entity}, we know the original data must
+ * be deleted, but to preserve the user modifications we treat as an insert.
+ */
+public class EntityDelta implements Parcelable {
+ // TODO: optimize by using contentvalues pool, since we allocate so many of them
+
+ private static final String TAG = "EntityDelta";
+ private static final boolean LOGV = true;
+
+ /**
+ * Direct values from {@link Entity#getEntityValues()}.
+ */
+ private ValuesDelta mValues;
+
+ /**
+ * Internal map of children values from {@link Entity#getSubValues()}, which
+ * we store here sorted into {@link Data#MIMETYPE} bins.
+ */
+ private HashMap<String, ArrayList<ValuesDelta>> mEntries = Maps.newHashMap();
+
+ public EntityDelta() {
+ }
+
+ public EntityDelta(ValuesDelta values) {
+ mValues = values;
+ }
+
+ /**
+ * Build an {@link EntityDelta} using the given {@link Entity} as a
+ * starting point; the "before" snapshot.
+ */
+ public static EntityDelta fromBefore(Entity before) {
+ final EntityDelta entity = new EntityDelta();
+ entity.mValues = ValuesDelta.fromBefore(before.getEntityValues());
+ entity.mValues.setIdColumn(RawContacts._ID);
+ for (NamedContentValues namedValues : before.getSubValues()) {
+ entity.addEntry(ValuesDelta.fromBefore(namedValues.values));
+ }
+ return entity;
+ }
+
+ /**
+ * Merge the "after" values from the given {@link EntityDelta} onto the
+ * "before" state represented by this {@link EntityDelta}, discarding any
+ * existing "after" states. This is typically used when re-parenting changes
+ * onto an updated {@link Entity}.
+ */
+ public static EntityDelta mergeAfter(EntityDelta local, EntityDelta remote) {
+ // Bail early if trying to merge delete with missing local
+ final ValuesDelta remoteValues = remote.mValues;
+ if (local == null && (remoteValues.isDelete() || remoteValues.isTransient())) return null;
+
+ // Create local version if none exists yet
+ if (local == null) local = new EntityDelta();
+
+ if (LOGV) {
+ final Long localVersion = (local.mValues == null) ? null : local.mValues
+ .getAsLong(RawContacts.VERSION);
+ final Long remoteVersion = remote.mValues.getAsLong(RawContacts.VERSION);
+ Log.d(TAG, "Re-parenting from original version " + remoteVersion + " to "
+ + localVersion);
+ }
+
+ // Create values if needed, and merge "after" changes
+ local.mValues = ValuesDelta.mergeAfter(local.mValues, remote.mValues);
+
+ // Find matching local entry for each remote values, or create
+ for (ArrayList<ValuesDelta> mimeEntries : remote.mEntries.values()) {
+ for (ValuesDelta remoteEntry : mimeEntries) {
+ final Long childId = remoteEntry.getId();
+
+ // Find or create local match and merge
+ final ValuesDelta localEntry = local.getEntry(childId);
+ final ValuesDelta merged = ValuesDelta.mergeAfter(localEntry, remoteEntry);
+
+ if (localEntry == null && merged != null) {
+ // No local entry before, so insert
+ local.addEntry(merged);
+ }
+ }
+ }
+
+ return local;
+ }
+
+ public ValuesDelta getValues() {
+ return mValues;
+ }
+
+ public boolean isContactInsert() {
+ return mValues.isInsert();
+ }
+
+ /**
+ * Get the {@link ValuesDelta} child marked as {@link Data#IS_PRIMARY},
+ * which may return null when no entry exists.
+ */
+ public ValuesDelta getPrimaryEntry(String mimeType) {
+ final ArrayList<ValuesDelta> mimeEntries = getMimeEntries(mimeType, false);
+ if (mimeEntries == null) return null;
+
+ for (ValuesDelta entry : mimeEntries) {
+ if (entry.isPrimary()) {
+ return entry;
+ }
+ }
+
+ // When no direct primary, return something
+ return mimeEntries.size() > 0 ? mimeEntries.get(0) : null;
+ }
+
+ /**
+ * calls {@link #getSuperPrimaryEntry(String, boolean)} with true
+ * @see #getSuperPrimaryEntry(String, boolean)
+ */
+ public ValuesDelta getSuperPrimaryEntry(String mimeType) {
+ return getSuperPrimaryEntry(mimeType, true);
+ }
+
+ /**
+ * Returns the super-primary entry for the given mime type
+ * @param forceSelection if true, will try to return some value even if a super-primary
+ * doesn't exist (may be a primary, or just a random item
+ * @return
+ */
+ public ValuesDelta getSuperPrimaryEntry(String mimeType, boolean forceSelection) {
+ final ArrayList<ValuesDelta> mimeEntries = getMimeEntries(mimeType, false);
+ if (mimeEntries == null) return null;
+
+ ValuesDelta primary = null;
+ for (ValuesDelta entry : mimeEntries) {
+ if (entry.isSuperPrimary()) {
+ return entry;
+ } else if (entry.isPrimary()) {
+ primary = entry;
+ }
+ }
+
+ if (!forceSelection) {
+ return null;
+ }
+
+ // When no direct super primary, return something
+ if (primary != null) {
+ return primary;
+ }
+ return mimeEntries.size() > 0 ? mimeEntries.get(0) : null;
+ }
+
+ /**
+ * Return the list of child {@link ValuesDelta} from our optimized map,
+ * creating the list if requested.
+ */
+ private ArrayList<ValuesDelta> getMimeEntries(String mimeType, boolean lazyCreate) {
+ ArrayList<ValuesDelta> mimeEntries = mEntries.get(mimeType);
+ if (mimeEntries == null && lazyCreate) {
+ mimeEntries = Lists.newArrayList();
+ mEntries.put(mimeType, mimeEntries);
+ }
+ return mimeEntries;
+ }
+
+ public ArrayList<ValuesDelta> getMimeEntries(String mimeType) {
+ return getMimeEntries(mimeType, false);
+ }
+
+ public int getMimeEntriesCount(String mimeType, boolean onlyVisible) {
+ final ArrayList<ValuesDelta> mimeEntries = getMimeEntries(mimeType);
+ if (mimeEntries == null) return 0;
+
+ int count = 0;
+ for (ValuesDelta child : mimeEntries) {
+ // Skip deleted items when requesting only visible
+ if (onlyVisible && !child.isVisible()) continue;
+ count++;
+ }
+ return count;
+ }
+
+ public boolean hasMimeEntries(String mimeType) {
+ return mEntries.containsKey(mimeType);
+ }
+
+ public ValuesDelta addEntry(ValuesDelta entry) {
+ final String mimeType = entry.getMimetype();
+ getMimeEntries(mimeType, true).add(entry);
+ return entry;
+ }
+
+ /**
+ * Find entry with the given {@link BaseColumns#_ID} value.
+ */
+ public ValuesDelta getEntry(Long childId) {
+ if (childId == null) {
+ // Requesting an "insert" entry, which has no "before"
+ return null;
+ }
+
+ // Search all children for requested entry
+ for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
+ for (ValuesDelta entry : mimeEntries) {
+ if (childId.equals(entry.getId())) {
+ return entry;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the total number of {@link ValuesDelta} contained.
+ */
+ public int getEntryCount(boolean onlyVisible) {
+ int count = 0;
+ for (String mimeType : mEntries.keySet()) {
+ count += getMimeEntriesCount(mimeType, onlyVisible);
+ }
+ return count;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof EntityDelta) {
+ final EntityDelta other = (EntityDelta)object;
+
+ // Equality failed if parent values different
+ if (!other.mValues.equals(mValues)) return false;
+
+ for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
+ for (ValuesDelta child : mimeEntries) {
+ // Equality failed if any children unmatched
+ if (!other.containsEntry(child)) return false;
+ }
+ }
+
+ // Passed all tests, so equal
+ return true;
+ }
+ return false;
+ }
+
+ private boolean containsEntry(ValuesDelta entry) {
+ for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
+ for (ValuesDelta child : mimeEntries) {
+ // Contained if we find any child that matches
+ if (child.equals(entry)) return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Mark this entire object deleted, including any {@link ValuesDelta}.
+ */
+ public void markDeleted() {
+ this.mValues.markDeleted();
+ for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
+ for (ValuesDelta child : mimeEntries) {
+ child.markDeleted();
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("\n(");
+ builder.append(mValues.toString());
+ builder.append(") = {");
+ for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
+ for (ValuesDelta child : mimeEntries) {
+ builder.append("\n\t");
+ child.toString(builder);
+ }
+ }
+ builder.append("\n}\n");
+ return builder.toString();
+ }
+
+ /**
+ * Consider building the given {@link ContentProviderOperation.Builder} and
+ * appending it to the given list, which only happens if builder is valid.
+ */
+ private void possibleAdd(ArrayList<ContentProviderOperation> diff,
+ ContentProviderOperation.Builder builder) {
+ if (builder != null) {
+ diff.add(builder.build());
+ }
+ }
+
+ /**
+ * Build a list of {@link ContentProviderOperation} that will assert any
+ * "before" state hasn't changed. This is maintained separately so that all
+ * asserts can take place before any updates occur.
+ */
+ public void buildAssert(ArrayList<ContentProviderOperation> buildInto) {
+ final boolean isContactInsert = mValues.isInsert();
+ if (!isContactInsert) {
+ // Assert version is consistent while persisting changes
+ final Long beforeId = mValues.getId();
+ final Long beforeVersion = mValues.getAsLong(RawContacts.VERSION);
+ if (beforeId == null || beforeVersion == null) return;
+
+ final ContentProviderOperation.Builder builder = ContentProviderOperation
+ .newAssertQuery(RawContacts.CONTENT_URI);
+ builder.withSelection(RawContacts._ID + "=" + beforeId, null);
+ builder.withValue(RawContacts.VERSION, beforeVersion);
+ buildInto.add(builder.build());
+ }
+ }
+
+ /**
+ * Build a list of {@link ContentProviderOperation} that will transform the
+ * current "before" {@link Entity} state into the modified state which this
+ * {@link EntityDelta} represents.
+ */
+ public void buildDiff(ArrayList<ContentProviderOperation> buildInto) {
+ final int firstIndex = buildInto.size();
+
+ final boolean isContactInsert = mValues.isInsert();
+ final boolean isContactDelete = mValues.isDelete();
+ final boolean isContactUpdate = !isContactInsert && !isContactDelete;
+
+ final Long beforeId = mValues.getId();
+
+ Builder builder;
+
+ // Build possible operation at Contact level
+ builder = mValues.buildDiff(RawContacts.CONTENT_URI);
+ possibleAdd(buildInto, builder);
+
+ // Build operations for all children
+ for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
+ for (ValuesDelta child : mimeEntries) {
+ // Ignore children if parent was deleted
+ if (isContactDelete) continue;
+
+ builder = child.buildDiff(Data.CONTENT_URI);
+ if (child.isInsert()) {
+ if (isContactInsert) {
+ // Parent is brand new insert, so back-reference _id
+ builder.withValueBackReference(Data.RAW_CONTACT_ID, firstIndex);
+ } else {
+ // Inserting under existing, so fill with known _id
+ builder.withValue(Data.RAW_CONTACT_ID, beforeId);
+ }
+ } else if (isContactInsert && builder != null) {
+ // Child must be insert when Contact insert
+ throw new IllegalArgumentException("When parent insert, child must be also");
+ }
+ possibleAdd(buildInto, builder);
+ }
+ }
+
+ final boolean addedOperations = buildInto.size() > firstIndex;
+ if (addedOperations && isContactUpdate) {
+ // Suspend aggregation while persisting updates
+ builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_SUSPENDED);
+ buildInto.add(firstIndex, builder.build());
+
+ // Restore aggregation as last operation
+ builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_DEFAULT);
+ buildInto.add(builder.build());
+ }
+ }
+
+ /**
+ * Build a {@link ContentProviderOperation} that changes
+ * {@link RawContacts#AGGREGATION_MODE} to the given value.
+ */
+ protected Builder buildSetAggregationMode(Long beforeId, int mode) {
+ Builder builder = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI);
+ builder.withValue(RawContacts.AGGREGATION_MODE, mode);
+ builder.withSelection(RawContacts._ID + "=" + beforeId, null);
+ return builder;
+ }
+
+ /** {@inheritDoc} */
+ public int describeContents() {
+ // Nothing special about this parcel
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ public void writeToParcel(Parcel dest, int flags) {
+ final int size = this.getEntryCount(false);
+ dest.writeInt(size);
+ dest.writeParcelable(mValues, flags);
+ for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
+ for (ValuesDelta child : mimeEntries) {
+ dest.writeParcelable(child, flags);
+ }
+ }
+ }
+
+ public void readFromParcel(Parcel source) {
+ final int size = source.readInt();
+ mValues = source.<ValuesDelta> readParcelable(null);
+ for (int i = 0; i < size; i++) {
+ final ValuesDelta child = source.<ValuesDelta> readParcelable(null);
+ this.addEntry(child);
+ }
+ }
+
+ public static final Parcelable.Creator<EntityDelta> CREATOR = new Parcelable.Creator<EntityDelta>() {
+ public EntityDelta createFromParcel(Parcel in) {
+ final EntityDelta state = new EntityDelta();
+ state.readFromParcel(in);
+ return state;
+ }
+
+ public EntityDelta[] newArray(int size) {
+ return new EntityDelta[size];
+ }
+ };
+
+ /**
+ * Type of {@link ContentValues} that maintains both an original state and a
+ * modified version of that state. This allows us to build insert, update,
+ * or delete operations based on a "before" {@link Entity} snapshot.
+ */
+ public static class ValuesDelta implements Parcelable {
+ protected ContentValues mBefore;
+ protected ContentValues mAfter;
+ protected String mIdColumn = BaseColumns._ID;
+ private boolean mFromTemplate;
+
+ /**
+ * Next value to assign to {@link #mIdColumn} when building an insert
+ * operation through {@link #fromAfter(ContentValues)}. This is used so
+ * we can concretely reference this {@link ValuesDelta} before it has
+ * been persisted.
+ */
+ protected static int sNextInsertId = -1;
+
+ protected ValuesDelta() {
+ }
+
+ /**
+ * Create {@link ValuesDelta}, using the given object as the
+ * "before" state, usually from an {@link Entity}.
+ */
+ public static ValuesDelta fromBefore(ContentValues before) {
+ final ValuesDelta entry = new ValuesDelta();
+ entry.mBefore = before;
+ entry.mAfter = new ContentValues();
+ return entry;
+ }
+
+ /**
+ * Create {@link ValuesDelta}, using the given object as the "after"
+ * state, usually when we are inserting a row instead of updating.
+ */
+ public static ValuesDelta fromAfter(ContentValues after) {
+ final ValuesDelta entry = new ValuesDelta();
+ entry.mBefore = null;
+ entry.mAfter = after;
+
+ // Assign temporary id which is dropped before insert.
+ entry.mAfter.put(entry.mIdColumn, sNextInsertId--);
+ return entry;
+ }
+
+ public ContentValues getAfter() {
+ return mAfter;
+ }
+
+ public String getAsString(String key) {
+ if (mAfter != null && mAfter.containsKey(key)) {
+ return mAfter.getAsString(key);
+ } else if (mBefore != null && mBefore.containsKey(key)) {
+ return mBefore.getAsString(key);
+ } else {
+ return null;
+ }
+ }
+
+ public byte[] getAsByteArray(String key) {
+ if (mAfter != null && mAfter.containsKey(key)) {
+ return mAfter.getAsByteArray(key);
+ } else if (mBefore != null && mBefore.containsKey(key)) {
+ return mBefore.getAsByteArray(key);
+ } else {
+ return null;
+ }
+ }
+
+ public Long getAsLong(String key) {
+ if (mAfter != null && mAfter.containsKey(key)) {
+ return mAfter.getAsLong(key);
+ } else if (mBefore != null && mBefore.containsKey(key)) {
+ return mBefore.getAsLong(key);
+ } else {
+ return null;
+ }
+ }
+
+ public Integer getAsInteger(String key) {
+ return getAsInteger(key, null);
+ }
+
+ public Integer getAsInteger(String key, Integer defaultValue) {
+ if (mAfter != null && mAfter.containsKey(key)) {
+ return mAfter.getAsInteger(key);
+ } else if (mBefore != null && mBefore.containsKey(key)) {
+ return mBefore.getAsInteger(key);
+ } else {
+ return defaultValue;
+ }
+ }
+
+ public String getMimetype() {
+ return getAsString(Data.MIMETYPE);
+ }
+
+ public Long getId() {
+ return getAsLong(mIdColumn);
+ }
+
+ /**
+ * Return a valid integer value suitable for {@link View#setId(int)}.
+ */
+ public int getViewId() {
+ final Long id = this.getId();
+ return (id == null) ? View.NO_ID : id.intValue();
+ }
+
+ public void setIdColumn(String idColumn) {
+ mIdColumn = idColumn;
+ }
+
+ public boolean isPrimary() {
+ final Long isPrimary = getAsLong(Data.IS_PRIMARY);
+ return isPrimary == null ? false : isPrimary != 0;
+ }
+
+ public void setFromTemplate(boolean isFromTemplate) {
+ mFromTemplate = isFromTemplate;
+ }
+
+ public boolean isFromTemplate() {
+ return mFromTemplate;
+ }
+
+ public boolean isSuperPrimary() {
+ final Long isSuperPrimary = getAsLong(Data.IS_SUPER_PRIMARY);
+ return isSuperPrimary == null ? false : isSuperPrimary != 0;
+ }
+
+ public boolean beforeExists() {
+ return (mBefore != null && mBefore.containsKey(mIdColumn));
+ }
+
+ public boolean isVisible() {
+ // When "after" is present, then visible
+ return (mAfter != null);
+ }
+
+ public boolean isDelete() {
+ // When "after" is wiped, action is "delete"
+ return beforeExists() && (mAfter == null);
+ }
+
+ public boolean isTransient() {
+ // When no "before" or "after", is transient
+ return (mBefore == null) && (mAfter == null);
+ }
+
+ public boolean isUpdate() {
+ // When "after" has some changes, action is "update"
+ return beforeExists() && (mAfter != null && mAfter.size() > 0);
+ }
+
+ public boolean isNoop() {
+ // When "after" has no changes, action is no-op
+ return beforeExists() && (mAfter != null && mAfter.size() == 0);
+ }
+
+ public boolean isInsert() {
+ // When no "before" id, and has "after", action is "insert"
+ return !beforeExists() && (mAfter != null);
+ }
+
+ public void markDeleted() {
+ mAfter = null;
+ }
+
+ /**
+ * Ensure that our internal structure is ready for storing updates.
+ */
+ private void ensureUpdate() {
+ if (mAfter == null) {
+ mAfter = new ContentValues();
+ }
+ }
+
+ public void put(String key, String value) {
+ ensureUpdate();
+ mAfter.put(key, value);
+ }
+
+ public void put(String key, byte[] value) {
+ ensureUpdate();
+ mAfter.put(key, value);
+ }
+
+ public void put(String key, int value) {
+ ensureUpdate();
+ mAfter.put(key, value);
+ }
+
+ /**
+ * Return set of all keys defined through this object.
+ */
+ public Set<String> keySet() {
+ final HashSet<String> keys = Sets.newHashSet();
+
+ if (mBefore != null) {
+ for (Map.Entry<String, Object> entry : mBefore.valueSet()) {
+ keys.add(entry.getKey());
+ }
+ }
+
+ if (mAfter != null) {
+ for (Map.Entry<String, Object> entry : mAfter.valueSet()) {
+ keys.add(entry.getKey());
+ }
+ }
+
+ return keys;
+ }
+
+ /**
+ * Return complete set of "before" and "after" values mixed together,
+ * giving full state regardless of edits.
+ */
+ public ContentValues getCompleteValues() {
+ final ContentValues values = new ContentValues();
+ if (mBefore != null) {
+ values.putAll(mBefore);
+ }
+ if (mAfter != null) {
+ values.putAll(mAfter);
+ }
+ if (values.containsKey(GroupMembership.GROUP_ROW_ID)) {
+ // Clear to avoid double-definitions, and prefer rows
+ values.remove(GroupMembership.GROUP_SOURCE_ID);
+ }
+
+ return values;
+ }
+
+ /**
+ * Merge the "after" values from the given {@link ValuesDelta},
+ * discarding any existing "after" state. This is typically used when
+ * re-parenting changes onto an updated {@link Entity}.
+ */
+ public static ValuesDelta mergeAfter(ValuesDelta local, ValuesDelta remote) {
+ // Bail early if trying to merge delete with missing local
+ if (local == null && (remote.isDelete() || remote.isTransient())) return null;
+
+ // Create local version if none exists yet
+ if (local == null) local = new ValuesDelta();
+
+ if (!local.beforeExists()) {
+ // Any "before" record is missing, so take all values as "insert"
+ local.mAfter = remote.getCompleteValues();
+ } else {
+ // Existing "update" with only "after" values
+ local.mAfter = remote.mAfter;
+ }
+
+ return local;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof ValuesDelta) {
+ // Only exactly equal with both are identical subsets
+ final ValuesDelta other = (ValuesDelta)object;
+ return this.subsetEquals(other) && other.subsetEquals(this);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ toString(builder);
+ return builder.toString();
+ }
+
+ /**
+ * Helper for building string representation, leveraging the given
+ * {@link StringBuilder} to minimize allocations.
+ */
+ public void toString(StringBuilder builder) {
+ builder.append("{ ");
+ for (String key : this.keySet()) {
+ builder.append(key);
+ builder.append("=");
+ builder.append(this.getAsString(key));
+ builder.append(", ");
+ }
+ builder.append("}");
+ }
+
+ /**
+ * Check if the given {@link ValuesDelta} is both a subset of this
+ * object, and any defined keys have equal values.
+ */
+ public boolean subsetEquals(ValuesDelta other) {
+ for (String key : this.keySet()) {
+ final String ourValue = this.getAsString(key);
+ final String theirValue = other.getAsString(key);
+ if (ourValue == null) {
+ // If they have value when we're null, no match
+ if (theirValue != null) return false;
+ } else {
+ // If both values defined and aren't equal, no match
+ if (!ourValue.equals(theirValue)) return false;
+ }
+ }
+ // All values compared and matched
+ return true;
+ }
+
+ /**
+ * Build a {@link ContentProviderOperation} that will transform our
+ * "before" state into our "after" state, using insert, update, or
+ * delete as needed.
+ */
+ public ContentProviderOperation.Builder buildDiff(Uri targetUri) {
+ Builder builder = null;
+ if (isInsert()) {
+ // Changed values are "insert" back-referenced to Contact
+ mAfter.remove(mIdColumn);
+ builder = ContentProviderOperation.newInsert(targetUri);
+ builder.withValues(mAfter);
+ } else if (isDelete()) {
+ // When marked for deletion and "before" exists, then "delete"
+ builder = ContentProviderOperation.newDelete(targetUri);
+ builder.withSelection(mIdColumn + "=" + getId(), null);
+ } else if (isUpdate()) {
+ // When has changes and "before" exists, then "update"
+ builder = ContentProviderOperation.newUpdate(targetUri);
+ builder.withSelection(mIdColumn + "=" + getId(), null);
+ builder.withValues(mAfter);
+ }
+ return builder;
+ }
+
+ /** {@inheritDoc} */
+ public int describeContents() {
+ // Nothing special about this parcel
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mBefore, flags);
+ dest.writeParcelable(mAfter, flags);
+ dest.writeString(mIdColumn);
+ }
+
+ public void readFromParcel(Parcel source) {
+ mBefore = source.<ContentValues> readParcelable(null);
+ mAfter = source.<ContentValues> readParcelable(null);
+ mIdColumn = source.readString();
+ }
+
+ public static final Parcelable.Creator<ValuesDelta> CREATOR = new Parcelable.Creator<ValuesDelta>() {
+ public ValuesDelta createFromParcel(Parcel in) {
+ final ValuesDelta values = new ValuesDelta();
+ values.readFromParcel(in);
+ return values;
+ }
+
+ public ValuesDelta[] newArray(int size) {
+ return new ValuesDelta[size];
+ }
+ };
+ }
+}
diff --git a/src/com/android/contacts/model/EntityDiff.java b/src/com/android/contacts/model/EntityDiff.java
new file mode 100644
index 0000000..ea46567
--- /dev/null
+++ b/src/com/android/contacts/model/EntityDiff.java
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.content.Entity;
+import android.content.ContentProviderOperation.Builder;
+import android.content.Entity.NamedContentValues;
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+
+/**
+ * Describes a set of {@link ContentProviderOperation} that need to be
+ * executed to transform a database from one {@link Entity} to another.
+ */
+@Deprecated
+public class EntityDiff extends ArrayList<ContentProviderOperation> {
+ private EntityDiff() {
+ }
+
+ /**
+ * Build the set of {@link ContentProviderOperation} needed to translate
+ * from "before" to "after". Tries its best to keep operations to
+ * minimal number required. Assumes that all {@link ContentValues} are
+ * keyed using {@link BaseColumns#_ID} values.
+ */
+ public static EntityDiff buildDiff(Entity before, Entity after, Uri targetUri,
+ String childForeignKey) {
+ final EntityDiff diff = new EntityDiff();
+
+ Builder builder;
+ ContentValues values;
+
+ if (before == null) {
+ // Before doesn't exist, so insert "after" values
+ builder = ContentProviderOperation.newInsert(targetUri);
+ builder.withValues(after.getEntityValues());
+ diff.add(builder.build());
+
+ for (NamedContentValues child : after.getSubValues()) {
+ // Add builder with reference to original _id when needed
+ builder = ContentProviderOperation.newInsert(child.uri);
+ builder.withValues(child.values);
+ if (childForeignKey != null) {
+ builder.withValueBackReference(childForeignKey, 0);
+ }
+ diff.add(builder.build());
+ }
+
+ } else if (after == null) {
+ // After doesn't exist, so delete "before" values
+ for (NamedContentValues child : before.getSubValues()) {
+ builder = ContentProviderOperation.newDelete(child.uri);
+ builder.withSelection(getSelectIdClause(child.values), null);
+ diff.add(builder.build());
+ }
+
+ builder = ContentProviderOperation.newDelete(targetUri);
+ builder.withSelection(getSelectIdClause(before.getEntityValues()), null);
+ diff.add(builder.build());
+
+ } else {
+ // Somewhere between, so update any changed values
+ values = after.getEntityValues();
+ if (!before.getEntityValues().equals(values)) {
+ // Top-level values changed, so update
+ builder = ContentProviderOperation.newUpdate(targetUri);
+ builder.withSelection(getSelectIdClause(values), null);
+ builder.withValues(values);
+ diff.add(builder.build());
+ }
+
+ // Build lookup maps for children on both sides
+ final HashMap<String, NamedContentValues> beforeChildren = buildChildrenMap(before);
+ final HashMap<String, NamedContentValues> afterChildren = buildChildrenMap(after);
+
+ // Walk through "before" children looking for deletes and updates
+ for (NamedContentValues beforeChild : beforeChildren.values()) {
+ final String key = buildChildKey(beforeChild);
+ final NamedContentValues afterChild = afterChildren.get(key);
+
+ if (afterChild == null) {
+ // After child doesn't exist, so delete "before" child
+ builder = ContentProviderOperation.newDelete(beforeChild.uri);
+ builder.withSelection(getSelectIdClause(beforeChild.values), null);
+ diff.add(builder.build());
+ } else if (!beforeChild.values.equals(afterChild.values)) {
+ // After child still exists, and is different, so update
+ values = afterChild.values;
+ builder = ContentProviderOperation.newUpdate(afterChild.uri);
+ builder.withSelection(getSelectIdClause(values), null);
+ builder.withValues(values);
+ diff.add(builder.build());
+ }
+
+ // Remove the now-handled "after" child
+ afterChildren.remove(key);
+ }
+
+ // Walk through remaining "after" children, which are inserts
+ for (NamedContentValues afterChild : afterChildren.values()) {
+ builder = ContentProviderOperation.newInsert(afterChild.uri);
+ builder.withValues(afterChild.values);
+ diff.add(builder.build());
+ }
+ }
+
+ return diff;
+ }
+
+ private static String buildChildKey(NamedContentValues child) {
+ return child.uri.toString() + child.values.getAsString(BaseColumns._ID);
+ }
+
+ private static String getSelectIdClause(ContentValues values) {
+ return BaseColumns._ID + "=" + values.getAsLong(BaseColumns._ID);
+ }
+
+ private static HashMap<String, NamedContentValues> buildChildrenMap(Entity entity) {
+ final ArrayList<NamedContentValues> children = entity.getSubValues();
+ final HashMap<String, NamedContentValues> childrenMap = new HashMap<String, NamedContentValues>(
+ children.size());
+ for (NamedContentValues child : children) {
+ final String key = buildChildKey(child);
+ childrenMap.put(key, child);
+ }
+ return childrenMap;
+ }
+}
diff --git a/src/com/android/contacts/model/EntityModifier.java b/src/com/android/contacts/model/EntityModifier.java
new file mode 100644
index 0000000..fb3eba7
--- /dev/null
+++ b/src/com/android/contacts/model/EntityModifier.java
@@ -0,0 +1,548 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import com.android.contacts.ContactsUtils;
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.model.ContactsSource.EditField;
+import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.google.android.collect.Lists;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.Intents.Insert;
+import android.provider.ContactsContract;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Helper methods for modifying an {@link EntityDelta}, such as inserting
+ * new rows, or enforcing {@link ContactsSource}.
+ */
+public class EntityModifier {
+ private static final String TAG = "EntityModifier";
+
+ /**
+ * For the given {@link EntityDelta}, determine if the given
+ * {@link DataKind} could be inserted under specific
+ * {@link ContactsSource}.
+ */
+ public static boolean canInsert(EntityDelta state, DataKind kind) {
+ // Insert possible when have valid types and under overall maximum
+ final int visibleCount = state.getMimeEntriesCount(kind.mimeType, true);
+ final boolean validTypes = hasValidTypes(state, kind);
+ final boolean validOverall = (kind.typeOverallMax == -1)
+ || (visibleCount < kind.typeOverallMax);
+ return (validTypes && validOverall);
+ }
+
+ public static boolean hasValidTypes(EntityDelta state, DataKind kind) {
+ if (EntityModifier.hasEditTypes(kind)) {
+ return (getValidTypes(state, kind).size() > 0);
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Ensure that at least one of the given {@link DataKind} exists in the
+ * given {@link EntityDelta} state, and try creating one if none exist.
+ */
+ public static void ensureKindExists(EntityDelta state, ContactsSource source, String mimeType) {
+ final DataKind kind = source.getKindForMimetype(mimeType);
+ final boolean hasChild = state.getMimeEntriesCount(mimeType, true) > 0;
+
+ if (!hasChild && kind != null) {
+ // Create child when none exists and valid kind
+ final ValuesDelta child = insertChild(state, kind);
+ if (kind.mimeType.equals(Photo.CONTENT_ITEM_TYPE)) {
+ child.setFromTemplate(true);
+ }
+ }
+ }
+
+ /**
+ * For the given {@link EntityDelta} and {@link DataKind}, return the
+ * list possible {@link EditType} options available based on
+ * {@link ContactsSource}.
+ */
+ public static ArrayList<EditType> getValidTypes(EntityDelta state, DataKind kind) {
+ return getValidTypes(state, kind, null, true, null);
+ }
+
+ /**
+ * For the given {@link EntityDelta} and {@link DataKind}, return the
+ * list possible {@link EditType} options available based on
+ * {@link ContactsSource}.
+ *
+ * @param forceInclude Always include this {@link EditType} in the returned
+ * list, even when an otherwise-invalid choice. This is useful
+ * when showing a dialog that includes the current type.
+ */
+ public static ArrayList<EditType> getValidTypes(EntityDelta state, DataKind kind,
+ EditType forceInclude) {
+ return getValidTypes(state, kind, forceInclude, true, null);
+ }
+
+ /**
+ * For the given {@link EntityDelta} and {@link DataKind}, return the
+ * list possible {@link EditType} options available based on
+ * {@link ContactsSource}.
+ *
+ * @param forceInclude Always include this {@link EditType} in the returned
+ * list, even when an otherwise-invalid choice. This is useful
+ * when showing a dialog that includes the current type.
+ * @param includeSecondary If true, include any valid types marked as
+ * {@link EditType#secondary}.
+ * @param typeCount When provided, will be used for the frequency count of
+ * each {@link EditType}, otherwise built using
+ * {@link #getTypeFrequencies(EntityDelta, DataKind)}.
+ */
+ private static ArrayList<EditType> getValidTypes(EntityDelta state, DataKind kind,
+ EditType forceInclude, boolean includeSecondary, SparseIntArray typeCount) {
+ final ArrayList<EditType> validTypes = Lists.newArrayList();
+
+ // Bail early if no types provided
+ if (!hasEditTypes(kind)) return validTypes;
+
+ if (typeCount == null) {
+ // Build frequency counts if not provided
+ typeCount = getTypeFrequencies(state, kind);
+ }
+
+ // Build list of valid types
+ final int overallCount = typeCount.get(FREQUENCY_TOTAL);
+ for (EditType type : kind.typeList) {
+ final boolean validOverall = (kind.typeOverallMax == -1 ? true
+ : overallCount < kind.typeOverallMax);
+ final boolean validSpecific = (type.specificMax == -1 ? true : typeCount
+ .get(type.rawValue) < type.specificMax);
+ final boolean validSecondary = (includeSecondary ? true : !type.secondary);
+ final boolean forcedInclude = type.equals(forceInclude);
+ if (forcedInclude || (validOverall && validSpecific && validSecondary)) {
+ // Type is valid when no limit, under limit, or forced include
+ validTypes.add(type);
+ }
+ }
+
+ return validTypes;
+ }
+
+ private static final int FREQUENCY_TOTAL = Integer.MIN_VALUE;
+
+ /**
+ * Count up the frequency that each {@link EditType} appears in the given
+ * {@link EntityDelta}. The returned {@link SparseIntArray} maps from
+ * {@link EditType#rawValue} to counts, with the total overall count stored
+ * as {@link #FREQUENCY_TOTAL}.
+ */
+ private static SparseIntArray getTypeFrequencies(EntityDelta state, DataKind kind) {
+ final SparseIntArray typeCount = new SparseIntArray();
+
+ // Find all entries for this kind, bailing early if none found
+ final List<ValuesDelta> mimeEntries = state.getMimeEntries(kind.mimeType);
+ if (mimeEntries == null) return typeCount;
+
+ int totalCount = 0;
+ for (ValuesDelta entry : mimeEntries) {
+ // Only count visible entries
+ if (!entry.isVisible()) continue;
+ totalCount++;
+
+ final EditType type = getCurrentType(entry, kind);
+ if (type != null) {
+ final int count = typeCount.get(type.rawValue);
+ typeCount.put(type.rawValue, count + 1);
+ }
+ }
+ typeCount.put(FREQUENCY_TOTAL, totalCount);
+ return typeCount;
+ }
+
+ /**
+ * Check if the given {@link DataKind} has multiple types that should be
+ * displayed for users to pick.
+ */
+ public static boolean hasEditTypes(DataKind kind) {
+ return kind.typeList != null && kind.typeList.size() > 0;
+ }
+
+ /**
+ * Find the {@link EditType} that describes the given
+ * {@link ValuesDelta} row, assuming the given {@link DataKind} dictates
+ * the possible types.
+ */
+ public static EditType getCurrentType(ValuesDelta entry, DataKind kind) {
+ final Long rawValue = entry.getAsLong(kind.typeColumn);
+ if (rawValue == null) return null;
+ return getType(kind, rawValue.intValue());
+ }
+
+ /**
+ * Find the {@link EditType} that describes the given {@link ContentValues} row,
+ * assuming the given {@link DataKind} dictates the possible types.
+ */
+ public static EditType getCurrentType(ContentValues entry, DataKind kind) {
+ if (kind.typeColumn == null) return null;
+ final Integer rawValue = entry.getAsInteger(kind.typeColumn);
+ if (rawValue == null) return null;
+ return getType(kind, rawValue);
+ }
+
+ /**
+ * Find the {@link EditType} that describes the given {@link Cursor} row,
+ * assuming the given {@link DataKind} dictates the possible types.
+ */
+ public static EditType getCurrentType(Cursor cursor, DataKind kind) {
+ if (kind.typeColumn == null) return null;
+ final int index = cursor.getColumnIndex(kind.typeColumn);
+ if (index == -1) return null;
+ final int rawValue = cursor.getInt(index);
+ return getType(kind, rawValue);
+ }
+
+ /**
+ * Find the {@link EditType} with the given {@link EditType#rawValue}.
+ */
+ public static EditType getType(DataKind kind, int rawValue) {
+ for (EditType type : kind.typeList) {
+ if (type.rawValue == rawValue) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the precedence for the the given {@link EditType#rawValue}, where
+ * lower numbers are higher precedence.
+ */
+ public static int getTypePrecedence(DataKind kind, int rawValue) {
+ for (int i = 0; i < kind.typeList.size(); i++) {
+ final EditType type = kind.typeList.get(i);
+ if (type.rawValue == rawValue) {
+ return i;
+ }
+ }
+ return Integer.MAX_VALUE;
+ }
+
+ /**
+ * Find the best {@link EditType} for a potential insert. The "best" is the
+ * first primary type that doesn't already exist. When all valid types
+ * exist, we pick the last valid option.
+ */
+ public static EditType getBestValidType(EntityDelta state, DataKind kind,
+ boolean includeSecondary, int exactValue) {
+ // Shortcut when no types
+ if (kind.typeColumn == null) return null;
+
+ // Find type counts and valid primary types, bail if none
+ final SparseIntArray typeCount = getTypeFrequencies(state, kind);
+ final ArrayList<EditType> validTypes = getValidTypes(state, kind, null, includeSecondary,
+ typeCount);
+ if (validTypes.size() == 0) return null;
+
+ // Keep track of the last valid type
+ final EditType lastType = validTypes.get(validTypes.size() - 1);
+
+ // Remove any types that already exist
+ Iterator<EditType> iterator = validTypes.iterator();
+ while (iterator.hasNext()) {
+ final EditType type = iterator.next();
+ final int count = typeCount.get(type.rawValue);
+
+ if (exactValue == type.rawValue) {
+ // Found exact value match
+ return type;
+ }
+
+ if (count > 0) {
+ // Type already appears, so don't consider
+ iterator.remove();
+ }
+ }
+
+ // Use the best remaining, otherwise the last valid
+ if (validTypes.size() > 0) {
+ return validTypes.get(0);
+ } else {
+ return lastType;
+ }
+ }
+
+ /**
+ * Insert a new child of kind {@link DataKind} into the given
+ * {@link EntityDelta}. Tries using the best {@link EditType} found using
+ * {@link #getBestValidType(EntityDelta, DataKind, boolean, int)}.
+ */
+ public static ValuesDelta insertChild(EntityDelta state, DataKind kind) {
+ // First try finding a valid primary
+ EditType bestType = getBestValidType(state, kind, false, Integer.MIN_VALUE);
+ if (bestType == null) {
+ // No valid primary found, so expand search to secondary
+ bestType = getBestValidType(state, kind, true, Integer.MIN_VALUE);
+ }
+ return insertChild(state, kind, bestType);
+ }
+
+ /**
+ * Insert a new child of kind {@link DataKind} into the given
+ * {@link EntityDelta}, marked with the given {@link EditType}.
+ */
+ public static ValuesDelta insertChild(EntityDelta state, DataKind kind, EditType type) {
+ // Bail early if invalid kind
+ if (kind == null) return null;
+ final ContentValues after = new ContentValues();
+
+ // Our parent CONTACT_ID is provided later
+ after.put(Data.MIMETYPE, kind.mimeType);
+
+ // Fill-in with any requested default values
+ if (kind.defaultValues != null) {
+ after.putAll(kind.defaultValues);
+ }
+
+ if (kind.typeColumn != null && type != null) {
+ // Set type, if provided
+ after.put(kind.typeColumn, type.rawValue);
+ }
+
+ final ValuesDelta child = ValuesDelta.fromAfter(after);
+ state.addEntry(child);
+ return child;
+ }
+
+ /**
+ * Processing to trim any empty {@link ValuesDelta} and {@link EntityDelta}
+ * from the given {@link EntitySet}, assuming the given {@link Sources}
+ * dictates the structure for various fields. This method ignores rows not
+ * described by the {@link ContactsSource}.
+ */
+ public static void trimEmpty(EntitySet set, Sources sources) {
+ for (EntityDelta state : set) {
+ final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ final ContactsSource source = sources.getInflatedSource(accountType,
+ ContactsSource.LEVEL_MIMETYPES);
+ trimEmpty(state, source);
+ }
+ }
+
+ /**
+ * Processing to trim any empty {@link ValuesDelta} rows from the given
+ * {@link EntityDelta}, assuming the given {@link ContactsSource} dictates
+ * the structure for various fields. This method ignores rows not described
+ * by the {@link ContactsSource}.
+ */
+ public static void trimEmpty(EntityDelta state, ContactsSource source) {
+ boolean hasValues = false;
+
+ // Walk through entries for each well-known kind
+ for (DataKind kind : source.getSortedDataKinds()) {
+ final String mimeType = kind.mimeType;
+ final ArrayList<ValuesDelta> entries = state.getMimeEntries(mimeType);
+ if (entries == null) continue;
+
+ for (ValuesDelta entry : entries) {
+ // Skip any values that haven't been touched
+ final boolean touched = entry.isInsert() || entry.isUpdate();
+ if (!touched) {
+ hasValues = true;
+ continue;
+ }
+
+ // Test and remove this row if empty and it isn't a photo from google
+ final boolean isGoogleSource = TextUtils.equals(GoogleSource.ACCOUNT_TYPE,
+ state.getValues().getAsString(RawContacts.ACCOUNT_TYPE));
+ final boolean isPhoto = TextUtils.equals(Photo.CONTENT_ITEM_TYPE, kind.mimeType);
+ final boolean isGooglePhoto = isPhoto && isGoogleSource;
+
+ if (EntityModifier.isEmpty(entry, kind) && !isGooglePhoto) {
+ // TODO: remove this verbose logging
+ Log.w(TAG, "Trimming: " + entry.toString());
+ entry.markDeleted();
+ } else if (!entry.isFromTemplate()) {
+ hasValues = true;
+ }
+ }
+ }
+ if (!hasValues) {
+ // Trim overall entity if no children exist
+ state.markDeleted();
+ }
+ }
+
+ /**
+ * Test if the given {@link ValuesDelta} would be considered "empty" in
+ * terms of {@link DataKind#fieldList}.
+ */
+ public static boolean isEmpty(ValuesDelta values, DataKind kind) {
+ // No defined fields mean this row is always empty
+ if (kind.fieldList == null) return true;
+
+ boolean hasValues = false;
+ for (EditField field : kind.fieldList) {
+ // If any field has values, we're not empty
+ final String value = values.getAsString(field.column);
+ if (ContactsUtils.isGraphic(value)) {
+ hasValues = true;
+ }
+ }
+
+ return !hasValues;
+ }
+
+ /**
+ * Parse the given {@link Bundle} into the given {@link EntityDelta} state,
+ * assuming the extras defined through {@link Intents}.
+ */
+ public static void parseExtras(Context context, ContactsSource source, EntityDelta state,
+ Bundle extras) {
+ if (extras == null || extras.size() == 0) {
+ // Bail early if no useful data
+ return;
+ }
+
+ {
+ // StructuredName
+ EntityModifier.ensureKindExists(state, source, StructuredName.CONTENT_ITEM_TYPE);
+ final ValuesDelta child = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
+
+ final String name = extras.getString(Insert.NAME);
+ if (ContactsUtils.isGraphic(name)) {
+ child.put(StructuredName.GIVEN_NAME, name);
+ }
+
+ final String phoneticName = extras.getString(Insert.PHONETIC_NAME);
+ if (ContactsUtils.isGraphic(phoneticName)) {
+ child.put(StructuredName.PHONETIC_GIVEN_NAME, phoneticName);
+ }
+ }
+
+ {
+ // StructuredPostal
+ final DataKind kind = source.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
+ parseExtras(state, kind, extras, Insert.POSTAL_TYPE, Insert.POSTAL,
+ StructuredPostal.STREET);
+ }
+
+ {
+ // Phone
+ final DataKind kind = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ parseExtras(state, kind, extras, Insert.PHONE_TYPE, Insert.PHONE, Phone.NUMBER);
+ parseExtras(state, kind, extras, Insert.SECONDARY_PHONE_TYPE, Insert.SECONDARY_PHONE,
+ Phone.NUMBER);
+ parseExtras(state, kind, extras, Insert.TERTIARY_PHONE_TYPE, Insert.TERTIARY_PHONE,
+ Phone.NUMBER);
+ }
+
+ {
+ // Email
+ final DataKind kind = source.getKindForMimetype(Email.CONTENT_ITEM_TYPE);
+ parseExtras(state, kind, extras, Insert.EMAIL_TYPE, Insert.EMAIL, Email.DATA);
+ parseExtras(state, kind, extras, Insert.SECONDARY_EMAIL_TYPE, Insert.SECONDARY_EMAIL,
+ Email.DATA);
+ parseExtras(state, kind, extras, Insert.TERTIARY_EMAIL_TYPE, Insert.TERTIARY_EMAIL,
+ Email.DATA);
+ }
+
+ {
+ // Im
+ final DataKind kind = source.getKindForMimetype(Im.CONTENT_ITEM_TYPE);
+ fixupLegacyImType(extras);
+ parseExtras(state, kind, extras, Insert.IM_PROTOCOL, Insert.IM_HANDLE, Im.DATA);
+ }
+ }
+
+ /**
+ * Attempt to parse legacy {@link Insert#IM_PROTOCOL} values, replacing them
+ * with updated values.
+ */
+ private static void fixupLegacyImType(Bundle bundle) {
+ final String encodedString = bundle.getString(Insert.IM_PROTOCOL);
+ if (encodedString == null) return;
+
+ try {
+ final Object protocol = android.provider.Contacts.ContactMethods
+ .decodeImProtocol(encodedString);
+ if (protocol instanceof Integer) {
+ bundle.putInt(Insert.IM_PROTOCOL, (Integer)protocol);
+ } else {
+ bundle.putString(Insert.IM_PROTOCOL, (String)protocol);
+ }
+ } catch (IllegalArgumentException e) {
+ // Ignore exception when legacy parser fails
+ }
+ }
+
+ /**
+ * Parse a specific entry from the given {@link Bundle} and insert into the
+ * given {@link EntityDelta}. Silently skips the insert when missing value
+ * or no valid {@link EditType} found.
+ *
+ * @param typeExtra {@link Bundle} key that holds the incoming
+ * {@link EditType#rawValue} value.
+ * @param valueExtra {@link Bundle} key that holds the incoming value.
+ * @param valueColumn Column to write value into {@link ValuesDelta}.
+ */
+ public static void parseExtras(EntityDelta state, DataKind kind, Bundle extras,
+ String typeExtra, String valueExtra, String valueColumn) {
+ final CharSequence value = extras.getCharSequence(valueExtra);
+
+ // Bail early if source doesn't handle this type
+ if (kind == null) return;
+
+ // Bail when can't insert type, or value missing
+ final boolean canInsert = EntityModifier.canInsert(state, kind);
+ final boolean validValue = (value != null && TextUtils.isGraphic(value));
+ if (!validValue || !canInsert) return;
+
+ // Find exact type when requested, otherwise best available type
+ final boolean hasType = extras.containsKey(typeExtra);
+ final int typeValue = extras.getInt(typeExtra, hasType ? BaseTypes.TYPE_CUSTOM
+ : Integer.MIN_VALUE);
+ final EditType editType = EntityModifier.getBestValidType(state, kind, true, typeValue);
+
+ // Create data row and fill with value
+ final ValuesDelta child = EntityModifier.insertChild(state, kind, editType);
+ child.put(valueColumn, value.toString());
+
+ if (editType != null && editType.customColumn != null) {
+ // Write down label when custom type picked
+ final String customType = extras.getString(typeExtra);
+ child.put(editType.customColumn, customType);
+ }
+ }
+}
diff --git a/src/com/android/contacts/model/EntitySet.java b/src/com/android/contacts/model/EntitySet.java
new file mode 100644
index 0000000..be2f70f
--- /dev/null
+++ b/src/com/android/contacts/model/EntitySet.java
@@ -0,0 +1,343 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.Entity;
+import android.content.EntityIterator;
+import android.content.ContentProviderOperation.Builder;
+import android.graphics.BitmapFactory;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.provider.ContactsContract.AggregationExceptions;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+
+import com.google.android.collect.Lists;
+
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+
+import java.util.ArrayList;
+
+/**
+ * Container for multiple {@link EntityDelta} objects, usually when editing
+ * together as an entire aggregate. Provides convenience methods for parceling
+ * and applying another {@link EntitySet} over it.
+ */
+public class EntitySet extends ArrayList<EntityDelta> implements Parcelable {
+ private boolean mSplitRawContacts;
+
+ private EntitySet() {
+ }
+
+ /**
+ * Create an {@link EntitySet} that contains the given {@link EntityDelta},
+ * usually when inserting a new {@link Contacts} entry.
+ */
+ public static EntitySet fromSingle(EntityDelta delta) {
+ final EntitySet state = new EntitySet();
+ state.add(delta);
+ return state;
+ }
+
+ /**
+ * Create an {@link EntitySet} based on {@link Contacts} specified by the
+ * given query parameters. This closes the {@link EntityIterator} when
+ * finished, so it doesn't subscribe to updates.
+ */
+ public static EntitySet fromQuery(ContentResolver resolver, String selection,
+ String[] selectionArgs, String sortOrder) {
+ EntityIterator iterator = null;
+ final EntitySet state = new EntitySet();
+ try {
+ // Perform background query to pull contact details
+ iterator = resolver.queryEntities(RawContacts.CONTENT_URI, selection, selectionArgs,
+ sortOrder);
+ while (iterator.hasNext()) {
+ // Read all contacts into local deltas to prepare for edits
+ final Entity before = iterator.next();
+ final EntityDelta entity = EntityDelta.fromBefore(before);
+ state.add(entity);
+ }
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Problem querying contact details", e);
+ } finally {
+ if (iterator != null) {
+ iterator.close();
+ }
+ }
+ return state;
+ }
+
+ /**
+ * Merge the "after" values from the given {@link EntitySet}, discarding any
+ * previous "after" states. This is typically used when re-parenting user
+ * edits onto an updated {@link EntitySet}.
+ */
+ public static EntitySet mergeAfter(EntitySet local, EntitySet remote) {
+ if (local == null) local = new EntitySet();
+
+ // For each entity in the remote set, try matching over existing
+ for (EntityDelta remoteEntity : remote) {
+ final Long rawContactId = remoteEntity.getValues().getId();
+
+ // Find or create local match and merge
+ final EntityDelta localEntity = local.getByRawContactId(rawContactId);
+ final EntityDelta merged = EntityDelta.mergeAfter(localEntity, remoteEntity);
+
+ if (localEntity == null && merged != null) {
+ // No local entry before, so insert
+ local.add(merged);
+ }
+ }
+
+ return local;
+ }
+
+ /**
+ * Build a list of {@link ContentProviderOperation} that will transform all
+ * the "before" {@link Entity} states into the modified state which all
+ * {@link EntityDelta} objects represent. This method specifically creates
+ * any {@link AggregationExceptions} rules needed to groups edits together.
+ */
+ public ArrayList<ContentProviderOperation> buildDiff() {
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+
+ final long rawContactId = this.findRawContactId();
+ int firstInsertRow = -1;
+
+ // First pass enforces versions remain consistent
+ for (EntityDelta delta : this) {
+ delta.buildAssert(diff);
+ }
+
+ final int assertMark = diff.size();
+ int backRefs[] = new int[size()];
+
+ int rawContactIndex = 0;
+
+ // Second pass builds actual operations
+ for (EntityDelta delta : this) {
+ final int firstBatch = diff.size();
+ backRefs[rawContactIndex++] = firstBatch;
+ delta.buildDiff(diff);
+
+ // Only create rules for inserts
+ if (!delta.isContactInsert()) continue;
+
+ // If we are going to split all contacts, there is no point in first combining them
+ if (mSplitRawContacts) continue;
+
+ if (rawContactId != -1) {
+ // Has existing contact, so bind to it strongly
+ final Builder builder = beginKeepTogether();
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId);
+ builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
+ diff.add(builder.build());
+
+ } else if (firstInsertRow == -1) {
+ // First insert case, so record row
+ firstInsertRow = firstBatch;
+
+ } else {
+ // Additional insert case, so point at first insert
+ final Builder builder = beginKeepTogether();
+ builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, firstInsertRow);
+ builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
+ diff.add(builder.build());
+ }
+ }
+
+ if (mSplitRawContacts) {
+ buildSplitContactDiff(diff, backRefs);
+ }
+
+ // No real changes if only left with asserts
+ if (diff.size() == assertMark) {
+ diff.clear();
+ }
+
+ return diff;
+ }
+
+ /**
+ * Start building a {@link ContentProviderOperation} that will keep two
+ * {@link RawContacts} together.
+ */
+ protected Builder beginKeepTogether() {
+ final Builder builder = ContentProviderOperation
+ .newUpdate(AggregationExceptions.CONTENT_URI);
+ builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
+ return builder;
+ }
+
+ /**
+ * Builds {@link AggregationExceptions} to split all constituent raw contacts into
+ * separate contacts.
+ */
+ private void buildSplitContactDiff(final ArrayList<ContentProviderOperation> diff,
+ int[] backRefs) {
+ int count = size();
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < count; j++) {
+ if (i != j) {
+ buildSplitContactDiff(diff, i, j, backRefs);
+ }
+ }
+ }
+ }
+
+ /**
+ * Construct a {@link AggregationExceptions#TYPE_KEEP_SEPARATE}.
+ */
+ private void buildSplitContactDiff(ArrayList<ContentProviderOperation> diff, int index1,
+ int index2, int[] backRefs) {
+ Builder builder =
+ ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI);
+ builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_SEPARATE);
+
+ Long rawContactId1 = get(index1).getValues().getAsLong(RawContacts._ID);
+ if (rawContactId1 != null && rawContactId1 >= 0) {
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
+ } else {
+ builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, backRefs[index1]);
+ }
+
+ Long rawContactId2 = get(index2).getValues().getAsLong(RawContacts._ID);
+ if (rawContactId2 != null && rawContactId2 >= 0) {
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
+ } else {
+ builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, backRefs[index2]);
+ }
+ diff.add(builder.build());
+ }
+
+ /**
+ * Search all contained {@link EntityDelta} for the first one with an
+ * existing {@link RawContacts#_ID} value. Usually used when creating
+ * {@link AggregationExceptions} during an update.
+ */
+ public long findRawContactId() {
+ for (EntityDelta delta : this) {
+ final Long rawContactId = delta.getValues().getAsLong(RawContacts._ID);
+ if (rawContactId != null && rawContactId >= 0) {
+ return rawContactId;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Find {@link RawContacts#_ID} of the requested {@link EntityDelta}.
+ */
+ public Long getRawContactId(int index) {
+ if (index >= 0 && index < this.size()) {
+ final EntityDelta delta = this.get(index);
+ final ValuesDelta values = delta.getValues();
+ if (values.isVisible()) {
+ return values.getAsLong(RawContacts._ID);
+ }
+ }
+ return null;
+ }
+
+ public EntityDelta getByRawContactId(Long rawContactId) {
+ final int index = this.indexOfRawContactId(rawContactId);
+ return (index == -1) ? null : this.get(index);
+ }
+
+ /**
+ * Find index of given {@link RawContacts#_ID} when present.
+ */
+ public int indexOfRawContactId(Long rawContactId) {
+ if (rawContactId == null) return -1;
+ final int size = this.size();
+ for (int i = 0; i < size; i++) {
+ final Long currentId = getRawContactId(i);
+ if (rawContactId.equals(currentId)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public ValuesDelta getSuperPrimaryEntry(final String mimeType) {
+ ValuesDelta primary = null;
+ ValuesDelta randomEntry = null;
+ for (EntityDelta delta : this) {
+ final ArrayList<ValuesDelta> mimeEntries = delta.getMimeEntries(mimeType);
+ if (mimeEntries == null) return null;
+
+ for (ValuesDelta entry : mimeEntries) {
+ if (entry.isSuperPrimary()) {
+ return entry;
+ } else if (primary == null && entry.isPrimary()) {
+ primary = entry;
+ } else if (randomEntry == null) {
+ randomEntry = entry;
+ }
+ }
+ }
+ // When no direct super primary, return something
+ if (primary != null) {
+ return primary;
+ }
+ return randomEntry;
+ }
+
+ public void splitRawContacts() {
+ mSplitRawContacts = true;
+ }
+
+ /** {@inheritDoc} */
+ public int describeContents() {
+ // Nothing special about this parcel
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ public void writeToParcel(Parcel dest, int flags) {
+ final int size = this.size();
+ dest.writeInt(size);
+ for (EntityDelta delta : this) {
+ dest.writeParcelable(delta, flags);
+ }
+ }
+
+ public void readFromParcel(Parcel source) {
+ final int size = source.readInt();
+ for (int i = 0; i < size; i++) {
+ this.add(source.<EntityDelta> readParcelable(null));
+ }
+ }
+
+ public static final Parcelable.Creator<EntitySet> CREATOR = new Parcelable.Creator<EntitySet>() {
+ public EntitySet createFromParcel(Parcel in) {
+ final EntitySet state = new EntitySet();
+ state.readFromParcel(in);
+ return state;
+ }
+
+ public EntitySet[] newArray(int size) {
+ return new EntitySet[size];
+ }
+ };
+}
diff --git a/src/com/android/contacts/model/ExchangeSource.java b/src/com/android/contacts/model/ExchangeSource.java
new file mode 100644
index 0000000..b46824c
--- /dev/null
+++ b/src/com/android/contacts/model/ExchangeSource.java
@@ -0,0 +1,285 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import com.android.contacts.R;
+import com.google.android.collect.Lists;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.Note;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+
+public class ExchangeSource extends FallbackSource {
+
+ public static final String ACCOUNT_TYPE = "com.android.exchange";
+
+ public ExchangeSource(String resPackageName) {
+ this.accountType = ACCOUNT_TYPE;
+ this.resPackageName = null;
+ this.summaryResPackageName = resPackageName;
+ }
+
+ @Override
+ protected void inflate(Context context, int inflateLevel) {
+
+ inflateStructuredName(inflateLevel);
+ inflateNickname(inflateLevel);
+ inflatePhone(inflateLevel);
+ inflateEmail(inflateLevel);
+ inflateStructuredPostal(inflateLevel);
+ inflateIm(inflateLevel);
+ inflateOrganization(inflateLevel);
+ inflatePhoto(inflateLevel);
+ inflateNote(inflateLevel);
+ inflateWebsite(inflateLevel);
+
+ setInflatedLevel(inflateLevel);
+ }
+
+ @Override
+ protected DataKind inflateStructuredName(int inflateLevel) {
+ final DataKind kind = super.inflateStructuredName(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+ FLAGS_PERSON_NAME).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
+ FLAGS_PERSON_NAME));
+ kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
+ FLAGS_PERSON_NAME).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
+ FLAGS_PERSON_NAME));
+ kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
+ FLAGS_PERSON_NAME).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
+ R.string.name_phonetic_given, FLAGS_PHONETIC).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
+ R.string.name_phonetic_family, FLAGS_PHONETIC).setOptional(true));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflateNickname(int inflateLevel) {
+ final DataKind kind = super.inflateNickname(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Nickname.NAME, R.string.nicknameLabelsGroup,
+ FLAGS_PERSON_NAME));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflatePhone(int inflateLevel) {
+ final DataKind kind = super.inflatePhone(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeColumn = Phone.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildPhoneType(Phone.TYPE_HOME).setSpecificMax(2));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE).setSpecificMax(1));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_WORK).setSpecificMax(2));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_WORK).setSecondary(true)
+ .setSpecificMax(1));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_HOME).setSecondary(true)
+ .setSpecificMax(1));
+ kind.typeList
+ .add(buildPhoneType(Phone.TYPE_PAGER).setSecondary(true).setSpecificMax(1));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_CAR).setSecondary(true).setSpecificMax(1));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_COMPANY_MAIN).setSecondary(true)
+ .setSpecificMax(1));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MMS).setSecondary(true).setSpecificMax(1));
+ kind.typeList
+ .add(buildPhoneType(Phone.TYPE_RADIO).setSecondary(true).setSpecificMax(1));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_ASSISTANT).setSecondary(true)
+ .setSpecificMax(1).setCustomColumn(Phone.LABEL));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflateEmail(int inflateLevel) {
+ final DataKind kind = super.inflateEmail(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeOverallMax = 3;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Email.DATA, R.string.emailLabelsGroup, FLAGS_EMAIL));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflateStructuredPostal(int inflateLevel) {
+ final DataKind kind = super.inflateStructuredPostal(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeColumn = StructuredPostal.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildPostalType(StructuredPostal.TYPE_WORK).setSpecificMax(1));
+ kind.typeList.add(buildPostalType(StructuredPostal.TYPE_HOME).setSpecificMax(1));
+ kind.typeList.add(buildPostalType(StructuredPostal.TYPE_OTHER).setSpecificMax(1));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(StructuredPostal.STREET, R.string.postal_street,
+ FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.CITY, R.string.postal_city,
+ FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.REGION, R.string.postal_region,
+ FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.POSTCODE, R.string.postal_postcode,
+ FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.COUNTRY, R.string.postal_country,
+ FLAGS_POSTAL).setOptional(true));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflateIm(int inflateLevel) {
+ final DataKind kind = super.inflateIm(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeOverallMax = 3;
+
+ // NOTE: even though a traditional "type" exists, for editing
+ // purposes we're using the protocol to pick labels
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Im.TYPE, Im.TYPE_OTHER);
+
+ kind.typeColumn = Im.PROTOCOL;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildImType(Im.PROTOCOL_AIM));
+ kind.typeList.add(buildImType(Im.PROTOCOL_MSN));
+ kind.typeList.add(buildImType(Im.PROTOCOL_YAHOO));
+ kind.typeList.add(buildImType(Im.PROTOCOL_SKYPE));
+ kind.typeList.add(buildImType(Im.PROTOCOL_QQ));
+ kind.typeList.add(buildImType(Im.PROTOCOL_GOOGLE_TALK));
+ kind.typeList.add(buildImType(Im.PROTOCOL_ICQ));
+ kind.typeList.add(buildImType(Im.PROTOCOL_JABBER));
+ kind.typeList.add(buildImType(Im.PROTOCOL_CUSTOM).setSecondary(true).setCustomColumn(
+ Im.CUSTOM_PROTOCOL));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Im.DATA, R.string.imLabelsGroup, FLAGS_EMAIL));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflateOrganization(int inflateLevel) {
+ final DataKind kind = super.inflateOrganization(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeOverallMax = 1;
+
+ kind.typeColumn = Organization.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildOrgType(Organization.TYPE_WORK).setSpecificMax(1));
+ kind.typeList.add(buildOrgType(Organization.TYPE_OTHER).setSpecificMax(1));
+ kind.typeList.add(buildOrgType(Organization.TYPE_CUSTOM).setSecondary(true)
+ .setSpecificMax(1));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Organization.COMPANY, R.string.ghostData_company,
+ FLAGS_GENERIC_NAME));
+ kind.fieldList.add(new EditField(Organization.TITLE, R.string.ghostData_title,
+ FLAGS_GENERIC_NAME));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflatePhoto(int inflateLevel) {
+ final DataKind kind = super.inflatePhoto(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Photo.PHOTO, -1, -1));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflateNote(int inflateLevel) {
+ final DataKind kind = super.inflateNote(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflateWebsite(int inflateLevel) {
+ final DataKind kind = super.inflateWebsite(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Website.URL, R.string.websiteLabelsGroup, FLAGS_WEBSITE));
+ }
+
+ return kind;
+ }
+
+ @Override
+ public int getHeaderColor(Context context) {
+ return 0xffd5ba96;
+ }
+
+ @Override
+ public int getSideBarColor(Context context) {
+ return 0xffb58e59;
+ }
+}
diff --git a/src/com/android/contacts/model/ExternalSource.java b/src/com/android/contacts/model/ExternalSource.java
new file mode 100644
index 0000000..d554c3a
--- /dev/null
+++ b/src/com/android/contacts/model/ExternalSource.java
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import java.io.IOException;
+import java.util.List;
+
+/*
+
+<!-- example of what SourceConstraints would look like in XML -->
+<!-- NOTE: may not directly match the current structure version -->
+
+<DataKind
+ mimeType="vnd.android.cursor.item/email"
+ title="@string/title_postal"
+ icon="@drawable/icon_postal"
+ weight="12"
+ editable="true">
+
+ <!-- these are defined using string-builder-ish -->
+ <ActionHeader></ActionHeader>
+ <ActionBody socialSummary="true" /> <!-- can pull together various columns -->
+
+ <!-- ordering handles precedence the "insert/add" case -->
+ <!-- assume uniform type when missing "column", use title in place -->
+ <EditTypes column="data5" overallMax="-1">
+ <EditType rawValue="0" label="@string/type_home" specificMax="-1" />
+ <EditType rawValue="1" label="@string/type_work" specificMax="-1" secondary="true" />
+ <EditType rawValue="4" label="@string/type_custom" customColumn="data6" specificMax="-1" secondary="true" />
+ </EditTypes>
+
+ <!-- when single edit field, simplifies edit case -->
+ <EditField column="data1" title="@string/field_family_name" android:inputType="textCapWords|textPhonetic" />
+ <EditField column="data2" title="@string/field_given_name" android:minLines="2" />
+ <EditField column="data3" title="@string/field_suffix" />
+
+</DataKind>
+
+*/
+
+/**
+ * Internal structure that represents constraints and styles for a specific data
+ * source, such as the various data types they support, including details on how
+ * those types should be rendered and edited.
+ * <p>
+ * In the future this may be inflated from XML defined by a data source.
+ */
+public class ExternalSource extends FallbackSource {
+ private static final String ACTION_SYNC_ADAPTER = "android.content.SyncAdapter";
+ private static final String METADATA_CONTACTS = "android.provider.CONTACTS_STRUCTURE";
+
+ private interface InflateTags {
+ final String CONTACTS_SOURCE = "ContactsSource";
+ final String CONTACTS_DATA_KIND = "ContactsDataKind";
+ }
+
+ public ExternalSource(String resPackageName) {
+ this.resPackageName = resPackageName;
+ this.summaryResPackageName = resPackageName;
+ }
+
+ /**
+ * Ensure that the constraint rules behind this {@link ContactsSource} have
+ * been inflated. Because this may involve parsing meta-data from
+ * {@link PackageManager}, it shouldn't be called from a UI thread.
+ */
+ @Override
+ public void inflate(Context context, int inflateLevel) {
+ // Handle unknown sources by searching their package
+ final PackageManager pm = context.getPackageManager();
+ final Intent syncAdapter = new Intent(ACTION_SYNC_ADAPTER);
+ final List<ResolveInfo> matches = pm.queryIntentServices(syncAdapter,
+ PackageManager.GET_META_DATA);
+ for (ResolveInfo info : matches) {
+ final XmlResourceParser parser = info.serviceInfo.loadXmlMetaData(pm,
+ METADATA_CONTACTS);
+ if (parser == null) continue;
+ inflate(context, parser);
+ }
+
+ // Bring in name and photo from fallback source, which are non-optional
+ inflateStructuredName(inflateLevel);
+ inflatePhoto(inflateLevel);
+
+ setInflatedLevel(inflateLevel);
+ }
+
+ /**
+ * Inflate this {@link ContactsSource} from the given parser. This may only
+ * load details matching the publicly-defined schema.
+ */
+ protected void inflate(Context context, XmlPullParser parser) {
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ try {
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Drain comments and whitespace
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("No start tag found");
+ }
+
+ if (!InflateTags.CONTACTS_SOURCE.equals(parser.getName())) {
+ throw new IllegalStateException("Top level element must be "
+ + InflateTags.CONTACTS_SOURCE);
+ }
+
+ // Parse all children kinds
+ final int depth = parser.getDepth();
+ while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
+ if (type == XmlPullParser.END_TAG
+ || !InflateTags.CONTACTS_DATA_KIND.equals(parser.getName())) {
+ continue;
+ }
+
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ android.R.styleable.ContactsDataKind);
+ final DataKind kind = new DataKind();
+
+ kind.mimeType = a
+ .getString(com.android.internal.R.styleable.ContactsDataKind_mimeType);
+ kind.iconRes = a.getResourceId(
+ com.android.internal.R.styleable.ContactsDataKind_icon, -1);
+
+ final String summaryColumn = a
+ .getString(com.android.internal.R.styleable.ContactsDataKind_summaryColumn);
+ if (summaryColumn != null) {
+ // Inflate a specific column as summary when requested
+ kind.actionHeader = new FallbackSource.SimpleInflater(summaryColumn);
+ }
+
+ final String detailColumn = a
+ .getString(com.android.internal.R.styleable.ContactsDataKind_detailColumn);
+ final boolean detailSocialSummary = a.getBoolean(
+ com.android.internal.R.styleable.ContactsDataKind_detailSocialSummary,
+ false);
+
+ if (detailSocialSummary) {
+ // Inflate social summary when requested
+ kind.actionBodySocial = true;
+ }
+
+ if (detailColumn != null) {
+ // Inflate specific column as summary
+ kind.actionBody = new FallbackSource.SimpleInflater(detailColumn);
+ }
+
+ addKind(kind);
+ }
+ } catch (XmlPullParserException e) {
+ throw new IllegalStateException("Problem reading XML", e);
+ } catch (IOException e) {
+ throw new IllegalStateException("Problem reading XML", e);
+ }
+ }
+
+ @Override
+ public int getHeaderColor(Context context) {
+ return 0xff6d86b4;
+ }
+
+ @Override
+ public int getSideBarColor(Context context) {
+ return 0xff6d86b4;
+ }
+}
diff --git a/src/com/android/contacts/model/FallbackSource.java b/src/com/android/contacts/model/FallbackSource.java
new file mode 100644
index 0000000..ca405eb
--- /dev/null
+++ b/src/com/android/contacts/model/FallbackSource.java
@@ -0,0 +1,634 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import com.android.contacts.R;
+import com.google.android.collect.Lists;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.Note;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.text.TextUtils;
+import android.view.inputmethod.EditorInfo;
+
+public class FallbackSource extends ContactsSource {
+ protected static final int FLAGS_PHONE = EditorInfo.TYPE_CLASS_PHONE;
+ protected static final int FLAGS_EMAIL = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+ protected static final int FLAGS_PERSON_NAME = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
+ protected static final int FLAGS_PHONETIC = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_PHONETIC;
+ protected static final int FLAGS_GENERIC_NAME = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
+ protected static final int FLAGS_NOTE = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+ protected static final int FLAGS_WEBSITE = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_URI;
+ protected static final int FLAGS_POSTAL = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS
+ | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+
+ public FallbackSource() {
+ this.accountType = null;
+ this.titleRes = R.string.account_phone;
+ this.iconRes = R.drawable.ic_launcher_contacts;
+ }
+
+ @Override
+ protected void inflate(Context context, int inflateLevel) {
+
+ inflateStructuredName(inflateLevel);
+ inflateNickname(inflateLevel);
+ inflatePhone(inflateLevel);
+ inflateEmail(inflateLevel);
+ inflateStructuredPostal(inflateLevel);
+ inflateIm(inflateLevel);
+ inflateOrganization(inflateLevel);
+ inflatePhoto(inflateLevel);
+ inflateNote(inflateLevel);
+ inflateWebsite(inflateLevel);
+ inflateEvent(inflateLevel);
+
+ setInflatedLevel(inflateLevel);
+
+ }
+
+ protected EditType buildPhoneType(int type) {
+ return new EditType(type, Phone.getTypeLabelResource(type));
+ }
+
+ protected EditType buildEmailType(int type) {
+ return new EditType(type, Email.getTypeLabelResource(type));
+ }
+
+ protected EditType buildPostalType(int type) {
+ return new EditType(type, StructuredPostal.getTypeLabelResource(type));
+ }
+
+ protected EditType buildImType(int type) {
+ return new EditType(type, Im.getProtocolLabelResource(type));
+ }
+
+ protected EditType buildOrgType(int type) {
+ return new EditType(type, Organization.getTypeLabelResource(type));
+ }
+
+ protected DataKind inflateStructuredName(int inflateLevel) {
+ DataKind kind = getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
+ R.string.nameLabelsGroup, -1, -1, true));
+ }
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+ FLAGS_PERSON_NAME).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
+ FLAGS_PERSON_NAME));
+ kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
+ FLAGS_PERSON_NAME).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
+ FLAGS_PERSON_NAME));
+ kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
+ FLAGS_PERSON_NAME).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
+ R.string.name_phonetic_given, FLAGS_PHONETIC).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
+ R.string.name_phonetic_middle, FLAGS_PHONETIC).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
+ R.string.name_phonetic_family, FLAGS_PHONETIC).setOptional(true));
+ }
+
+ return kind;
+ }
+
+ protected DataKind inflateNickname(int inflateLevel) {
+ DataKind kind = getKindForMimetype(Nickname.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(Nickname.CONTENT_ITEM_TYPE,
+ R.string.nicknameLabelsGroup, -1, 115, true));
+ kind.secondary = true;
+ kind.actionHeader = new SimpleInflater(R.string.nicknameLabelsGroup);
+ kind.actionBody = new SimpleInflater(Nickname.NAME);
+ }
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Nickname.TYPE, Nickname.TYPE_DEFAULT);
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Nickname.NAME, R.string.nicknameLabelsGroup,
+ FLAGS_PERSON_NAME));
+ }
+
+ return kind;
+ }
+
+ protected DataKind inflatePhone(int inflateLevel) {
+ DataKind kind = getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(Phone.CONTENT_ITEM_TYPE, R.string.phoneLabelsGroup,
+ android.R.drawable.sym_action_call, 10, true));
+ kind.iconAltRes = R.drawable.sym_action_sms;
+ kind.actionHeader = new PhoneActionInflater();
+ kind.actionAltHeader = new PhoneActionAltInflater();
+ kind.actionBody = new SimpleInflater(Phone.NUMBER);
+ }
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeColumn = Phone.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_WORK));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_WORK).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_HOME).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_PAGER).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_OTHER));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_CUSTOM).setSecondary(true).setCustomColumn(
+ Phone.LABEL));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_CALLBACK).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_CAR).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_COMPANY_MAIN).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_ISDN).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MAIN).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_OTHER_FAX).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_RADIO).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_TELEX).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_TTY_TDD).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_WORK_MOBILE).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_WORK_PAGER).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_ASSISTANT).setSecondary(true)
+ .setCustomColumn(Phone.LABEL));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MMS).setSecondary(true));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
+ }
+
+ return kind;
+ }
+
+ protected DataKind inflateEmail(int inflateLevel) {
+ DataKind kind = getKindForMimetype(Email.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(Email.CONTENT_ITEM_TYPE,
+ R.string.emailLabelsGroup, android.R.drawable.sym_action_email, 15, true));
+ kind.actionHeader = new EmailActionInflater();
+ kind.actionBody = new SimpleInflater(Email.DATA);
+ }
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeColumn = Email.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildEmailType(Email.TYPE_HOME));
+ kind.typeList.add(buildEmailType(Email.TYPE_WORK));
+ kind.typeList.add(buildEmailType(Email.TYPE_OTHER));
+ kind.typeList.add(buildEmailType(Email.TYPE_MOBILE));
+ kind.typeList.add(buildEmailType(Email.TYPE_CUSTOM).setSecondary(true).setCustomColumn(
+ Email.LABEL));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Email.DATA, R.string.emailLabelsGroup, FLAGS_EMAIL));
+ }
+
+ return kind;
+ }
+
+ protected DataKind inflateStructuredPostal(int inflateLevel) {
+ DataKind kind = getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(StructuredPostal.CONTENT_ITEM_TYPE,
+ R.string.postalLabelsGroup, R.drawable.sym_action_map, 25, true));
+ kind.actionHeader = new PostalActionInflater();
+ kind.actionBody = new SimpleInflater(StructuredPostal.FORMATTED_ADDRESS);
+ }
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeColumn = StructuredPostal.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildPostalType(StructuredPostal.TYPE_HOME));
+ kind.typeList.add(buildPostalType(StructuredPostal.TYPE_WORK));
+ kind.typeList.add(buildPostalType(StructuredPostal.TYPE_OTHER));
+ kind.typeList.add(buildPostalType(StructuredPostal.TYPE_CUSTOM).setSecondary(true)
+ .setCustomColumn(StructuredPostal.LABEL));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(StructuredPostal.STREET, R.string.postal_street,
+ FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.POBOX, R.string.postal_pobox,
+ FLAGS_POSTAL).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredPostal.NEIGHBORHOOD,
+ R.string.postal_neighborhood, FLAGS_POSTAL).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredPostal.CITY, R.string.postal_city,
+ FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.REGION, R.string.postal_region,
+ FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.POSTCODE, R.string.postal_postcode,
+ FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.COUNTRY, R.string.postal_country,
+ FLAGS_POSTAL).setOptional(true));
+ }
+
+ return kind;
+ }
+
+ protected DataKind inflateIm(int inflateLevel) {
+ DataKind kind = getKindForMimetype(Im.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(Im.CONTENT_ITEM_TYPE, R.string.imLabelsGroup,
+ android.R.drawable.sym_action_chat, 20, true));
+ kind.actionHeader = new ImActionInflater();
+ kind.actionBody = new SimpleInflater(Im.DATA);
+ }
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ // NOTE: even though a traditional "type" exists, for editing
+ // purposes we're using the protocol to pick labels
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Im.TYPE, Im.TYPE_OTHER);
+
+ kind.typeColumn = Im.PROTOCOL;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildImType(Im.PROTOCOL_AIM));
+ kind.typeList.add(buildImType(Im.PROTOCOL_MSN));
+ kind.typeList.add(buildImType(Im.PROTOCOL_YAHOO));
+ kind.typeList.add(buildImType(Im.PROTOCOL_SKYPE));
+ kind.typeList.add(buildImType(Im.PROTOCOL_QQ));
+ kind.typeList.add(buildImType(Im.PROTOCOL_GOOGLE_TALK));
+ kind.typeList.add(buildImType(Im.PROTOCOL_ICQ));
+ kind.typeList.add(buildImType(Im.PROTOCOL_JABBER));
+ kind.typeList.add(buildImType(Im.PROTOCOL_CUSTOM).setSecondary(true).setCustomColumn(
+ Im.CUSTOM_PROTOCOL));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Im.DATA, R.string.imLabelsGroup, FLAGS_EMAIL));
+ }
+
+ return kind;
+ }
+
+ protected DataKind inflateOrganization(int inflateLevel) {
+ DataKind kind = getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(Organization.CONTENT_ITEM_TYPE,
+ R.string.organizationLabelsGroup, R.drawable.sym_action_organization, 30, true));
+ kind.actionHeader = new SimpleInflater(Organization.COMPANY);
+ kind.actionBody = new SimpleInflater(Organization.TITLE);
+ }
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeColumn = Organization.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildOrgType(Organization.TYPE_WORK));
+ kind.typeList.add(buildOrgType(Organization.TYPE_OTHER));
+ kind.typeList.add(buildOrgType(Organization.TYPE_CUSTOM).setSecondary(true)
+ .setCustomColumn(Organization.LABEL));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Organization.COMPANY, R.string.ghostData_company,
+ FLAGS_GENERIC_NAME));
+ kind.fieldList.add(new EditField(Organization.TITLE, R.string.ghostData_title,
+ FLAGS_GENERIC_NAME));
+ }
+
+ return kind;
+ }
+
+ protected DataKind inflatePhoto(int inflateLevel) {
+ DataKind kind = getKindForMimetype(Photo.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(Photo.CONTENT_ITEM_TYPE, -1, -1, -1, true));
+ }
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Photo.PHOTO, -1, -1));
+ }
+
+ return kind;
+ }
+
+ protected DataKind inflateNote(int inflateLevel) {
+ DataKind kind = getKindForMimetype(Note.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(Note.CONTENT_ITEM_TYPE,
+ R.string.label_notes, R.drawable.sym_note, 110, true));
+ kind.secondary = true;
+ kind.actionHeader = new SimpleInflater(R.string.label_notes);
+ kind.actionBody = new SimpleInflater(Note.NOTE);
+ }
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
+ }
+
+ return kind;
+ }
+
+ protected DataKind inflateWebsite(int inflateLevel) {
+ DataKind kind = getKindForMimetype(Website.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(Website.CONTENT_ITEM_TYPE,
+ R.string.websiteLabelsGroup, -1, 120, true));
+ kind.secondary = true;
+ kind.actionHeader = new SimpleInflater(R.string.websiteLabelsGroup);
+ kind.actionBody = new SimpleInflater(Website.URL);
+ }
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Website.TYPE, Website.TYPE_OTHER);
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Website.URL, R.string.websiteLabelsGroup, FLAGS_WEBSITE));
+ }
+
+ return kind;
+ }
+
+ protected DataKind inflateEvent(int inflateLevel) {
+ DataKind kind = getKindForMimetype(Event.CONTENT_ITEM_TYPE);
+ if (kind == null) {
+ kind = addKind(new DataKind(Event.CONTENT_ITEM_TYPE,
+ R.string.eventLabelsGroup, -1, 150, false));
+ kind.secondary = true;
+ kind.actionHeader = new EventActionInflater();
+ kind.actionBody = new SimpleInflater(Event.START_DATE);
+ }
+
+ return kind;
+ }
+
+ /**
+ * Simple inflater that assumes a string resource has a "%s" that will be
+ * filled from the given column.
+ */
+ public static class SimpleInflater implements StringInflater {
+ private final int mStringRes;
+ private final String mColumnName;
+
+ public SimpleInflater(int stringRes) {
+ this(stringRes, null);
+ }
+
+ public SimpleInflater(String columnName) {
+ this(-1, columnName);
+ }
+
+ public SimpleInflater(int stringRes, String columnName) {
+ mStringRes = stringRes;
+ mColumnName = columnName;
+ }
+
+ public CharSequence inflateUsing(Context context, Cursor cursor) {
+ final int index = mColumnName != null ? cursor.getColumnIndex(mColumnName) : -1;
+ final boolean validString = mStringRes > 0;
+ final boolean validColumn = index != -1;
+
+ final CharSequence stringValue = validString ? context.getText(mStringRes) : null;
+ final CharSequence columnValue = validColumn ? cursor.getString(index) : null;
+
+ if (validString && validColumn) {
+ return String.format(stringValue.toString(), columnValue);
+ } else if (validString) {
+ return stringValue;
+ } else if (validColumn) {
+ return columnValue;
+ } else {
+ return null;
+ }
+ }
+
+ public CharSequence inflateUsing(Context context, ContentValues values) {
+ final boolean validColumn = values.containsKey(mColumnName);
+ final boolean validString = mStringRes > 0;
+
+ final CharSequence stringValue = validString ? context.getText(mStringRes) : null;
+ final CharSequence columnValue = validColumn ? values.getAsString(mColumnName) : null;
+
+ if (validString && validColumn) {
+ return String.format(stringValue.toString(), columnValue);
+ } else if (validString) {
+ return stringValue;
+ } else if (validColumn) {
+ return columnValue;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public static abstract class CommonInflater implements StringInflater {
+ protected abstract int getTypeLabelResource(Integer type);
+
+ protected boolean isCustom(Integer type) {
+ return type == BaseTypes.TYPE_CUSTOM;
+ }
+
+ protected String getTypeColumn() {
+ return Phone.TYPE;
+ }
+
+ protected String getLabelColumn() {
+ return Phone.LABEL;
+ }
+
+ protected CharSequence getTypeLabel(Resources res, Integer type, CharSequence label) {
+ final int labelRes = getTypeLabelResource(type);
+ if (type == null) {
+ return res.getText(labelRes);
+ } else if (isCustom(type)) {
+ return res.getString(labelRes, label == null ? "" : label);
+ } else {
+ return res.getText(labelRes);
+ }
+ }
+
+ public CharSequence inflateUsing(Context context, Cursor cursor) {
+ final Integer type = cursor.getInt(cursor.getColumnIndex(getTypeColumn()));
+ final String label = cursor.getString(cursor.getColumnIndex(getLabelColumn()));
+ return getTypeLabel(context.getResources(), type, label);
+ }
+
+ public CharSequence inflateUsing(Context context, ContentValues values) {
+ final Integer type = values.getAsInteger(getTypeColumn());
+ final String label = values.getAsString(getLabelColumn());
+ return getTypeLabel(context.getResources(), type, label);
+ }
+ }
+
+ public static class PhoneActionInflater extends CommonInflater {
+ @Override
+ protected boolean isCustom(Integer type) {
+ return type == Phone.TYPE_CUSTOM || type == Phone.TYPE_ASSISTANT;
+ }
+
+ @Override
+ protected int getTypeLabelResource(Integer type) {
+ if (type == null) return R.string.call_other;
+ switch (type) {
+ case Phone.TYPE_HOME: return R.string.call_home;
+ case Phone.TYPE_MOBILE: return R.string.call_mobile;
+ case Phone.TYPE_WORK: return R.string.call_work;
+ case Phone.TYPE_FAX_WORK: return R.string.call_fax_work;
+ case Phone.TYPE_FAX_HOME: return R.string.call_fax_home;
+ case Phone.TYPE_PAGER: return R.string.call_pager;
+ case Phone.TYPE_OTHER: return R.string.call_other;
+ case Phone.TYPE_CALLBACK: return R.string.call_callback;
+ case Phone.TYPE_CAR: return R.string.call_car;
+ case Phone.TYPE_COMPANY_MAIN: return R.string.call_company_main;
+ case Phone.TYPE_ISDN: return R.string.call_isdn;
+ case Phone.TYPE_MAIN: return R.string.call_main;
+ case Phone.TYPE_OTHER_FAX: return R.string.call_other_fax;
+ case Phone.TYPE_RADIO: return R.string.call_radio;
+ case Phone.TYPE_TELEX: return R.string.call_telex;
+ case Phone.TYPE_TTY_TDD: return R.string.call_tty_tdd;
+ case Phone.TYPE_WORK_MOBILE: return R.string.call_work_mobile;
+ case Phone.TYPE_WORK_PAGER: return R.string.call_work_pager;
+ case Phone.TYPE_ASSISTANT: return R.string.call_assistant;
+ case Phone.TYPE_MMS: return R.string.call_mms;
+ default: return R.string.call_custom;
+ }
+ }
+ }
+
+ public static class PhoneActionAltInflater extends CommonInflater {
+ @Override
+ protected boolean isCustom(Integer type) {
+ return (type == Phone.TYPE_CUSTOM || type == Phone.TYPE_ASSISTANT);
+ }
+
+ @Override
+ protected int getTypeLabelResource(Integer type) {
+ if (type == null) return R.string.sms_other;
+ switch (type) {
+ case Phone.TYPE_HOME: return R.string.sms_home;
+ case Phone.TYPE_MOBILE: return R.string.sms_mobile;
+ case Phone.TYPE_WORK: return R.string.sms_work;
+ case Phone.TYPE_FAX_WORK: return R.string.sms_fax_work;
+ case Phone.TYPE_FAX_HOME: return R.string.sms_fax_home;
+ case Phone.TYPE_PAGER: return R.string.sms_pager;
+ case Phone.TYPE_OTHER: return R.string.sms_other;
+ case Phone.TYPE_CALLBACK: return R.string.sms_callback;
+ case Phone.TYPE_CAR: return R.string.sms_car;
+ case Phone.TYPE_COMPANY_MAIN: return R.string.sms_company_main;
+ case Phone.TYPE_ISDN: return R.string.sms_isdn;
+ case Phone.TYPE_MAIN: return R.string.sms_main;
+ case Phone.TYPE_OTHER_FAX: return R.string.sms_other_fax;
+ case Phone.TYPE_RADIO: return R.string.sms_radio;
+ case Phone.TYPE_TELEX: return R.string.sms_telex;
+ case Phone.TYPE_TTY_TDD: return R.string.sms_tty_tdd;
+ case Phone.TYPE_WORK_MOBILE: return R.string.sms_work_mobile;
+ case Phone.TYPE_WORK_PAGER: return R.string.sms_work_pager;
+ case Phone.TYPE_ASSISTANT: return R.string.sms_assistant;
+ case Phone.TYPE_MMS: return R.string.sms_mms;
+ default: return R.string.sms_custom;
+ }
+ }
+ }
+
+ public static class EmailActionInflater extends CommonInflater {
+ @Override
+ protected int getTypeLabelResource(Integer type) {
+ if (type == null) return R.string.email;
+ switch (type) {
+ case Email.TYPE_HOME: return R.string.email_home;
+ case Email.TYPE_WORK: return R.string.email_work;
+ case Email.TYPE_OTHER: return R.string.email_other;
+ case Email.TYPE_MOBILE: return R.string.email_mobile;
+ default: return R.string.email_custom;
+ }
+ }
+ }
+
+ public static class EventActionInflater extends CommonInflater {
+ @Override
+ protected int getTypeLabelResource(Integer type) {
+ return Event.getTypeResource(type);
+ }
+ }
+
+ public static class PostalActionInflater extends CommonInflater {
+ @Override
+ protected int getTypeLabelResource(Integer type) {
+ if (type == null) return R.string.map_other;
+ switch (type) {
+ case StructuredPostal.TYPE_HOME: return R.string.map_home;
+ case StructuredPostal.TYPE_WORK: return R.string.map_work;
+ case StructuredPostal.TYPE_OTHER: return R.string.map_other;
+ default: return R.string.map_custom;
+ }
+ }
+ }
+
+ public static class ImActionInflater extends CommonInflater {
+ @Override
+ protected String getTypeColumn() {
+ return Im.PROTOCOL;
+ }
+
+ @Override
+ protected String getLabelColumn() {
+ return Im.CUSTOM_PROTOCOL;
+ }
+
+ @Override
+ protected int getTypeLabelResource(Integer type) {
+ if (type == null) return R.string.chat;
+ switch (type) {
+ case Im.PROTOCOL_AIM: return R.string.chat_aim;
+ case Im.PROTOCOL_MSN: return R.string.chat_msn;
+ case Im.PROTOCOL_YAHOO: return R.string.chat_yahoo;
+ case Im.PROTOCOL_SKYPE: return R.string.chat_skype;
+ case Im.PROTOCOL_QQ: return R.string.chat_qq;
+ case Im.PROTOCOL_GOOGLE_TALK: return R.string.chat_gtalk;
+ case Im.PROTOCOL_ICQ: return R.string.chat_icq;
+ case Im.PROTOCOL_JABBER: return R.string.chat_jabber;
+ case Im.PROTOCOL_NETMEETING: return R.string.chat;
+ default: return R.string.chat;
+ }
+ }
+ }
+
+ @Override
+ public int getHeaderColor(Context context) {
+ return 0xff7f93bc;
+ }
+
+ @Override
+ public int getSideBarColor(Context context) {
+ return 0xffbdc7b8;
+ }
+}
diff --git a/src/com/android/contacts/model/GoogleSource.java b/src/com/android/contacts/model/GoogleSource.java
new file mode 100644
index 0000000..a4b4cb2
--- /dev/null
+++ b/src/com/android/contacts/model/GoogleSource.java
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import com.android.contacts.R;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.google.android.collect.Lists;
+
+import android.accounts.Account;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.OperationApplicationException;
+import android.database.Cursor;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Groups;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts.Data;
+
+import java.util.ArrayList;
+
+public class GoogleSource extends FallbackSource {
+ public static final String ACCOUNT_TYPE = "com.google";
+ public GoogleSource(String resPackageName) {
+ this.accountType = ACCOUNT_TYPE;
+ this.resPackageName = null;
+ this.summaryResPackageName = resPackageName;
+ }
+
+ @Override
+ protected void inflate(Context context, int inflateLevel) {
+
+ inflateStructuredName(inflateLevel);
+ inflateNickname(inflateLevel);
+ inflatePhone(inflateLevel);
+ inflateEmail(inflateLevel);
+ inflateStructuredPostal(inflateLevel);
+ inflateIm(inflateLevel);
+ inflateOrganization(inflateLevel);
+ inflatePhoto(inflateLevel);
+ inflateNote(inflateLevel);
+ inflateWebsite(inflateLevel);
+ inflateEvent(inflateLevel);
+
+ // TODO: GOOGLE: GROUPMEMBERSHIP
+
+ setInflatedLevel(inflateLevel);
+
+ }
+
+ @Override
+ protected DataKind inflateStructuredName(int inflateLevel) {
+ return super.inflateStructuredName(inflateLevel);
+ }
+
+ @Override
+ protected DataKind inflateNickname(int inflateLevel) {
+ return super.inflateNickname(inflateLevel);
+ }
+
+ @Override
+ protected DataKind inflatePhone(int inflateLevel) {
+ final DataKind kind = super.inflatePhone(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeColumn = Phone.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_WORK));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_WORK).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_HOME).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_PAGER).setSecondary(true));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_OTHER));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_CUSTOM).setSecondary(true).setCustomColumn(
+ Phone.LABEL));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflateEmail(int inflateLevel) {
+ final DataKind kind = super.inflateEmail(ContactsSource.LEVEL_MIMETYPES);
+
+ if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
+ kind.typeColumn = Email.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildEmailType(Email.TYPE_HOME));
+ kind.typeList.add(buildEmailType(Email.TYPE_WORK));
+ kind.typeList.add(buildEmailType(Email.TYPE_OTHER));
+ kind.typeList.add(buildEmailType(Email.TYPE_CUSTOM).setSecondary(true).setCustomColumn(
+ Email.LABEL));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Email.DATA, R.string.emailLabelsGroup, FLAGS_EMAIL));
+ }
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind inflateStructuredPostal(int inflateLevel) {
+ return super.inflateStructuredPostal(inflateLevel);
+ }
+
+ @Override
+ protected DataKind inflateIm(int inflateLevel) {
+ return super.inflateIm(inflateLevel);
+ }
+
+ @Override
+ protected DataKind inflateOrganization(int inflateLevel) {
+ return super.inflateOrganization(inflateLevel);
+ }
+
+ @Override
+ protected DataKind inflatePhoto(int inflateLevel) {
+ return super.inflatePhoto(inflateLevel);
+ }
+
+ @Override
+ protected DataKind inflateNote(int inflateLevel) {
+ return super.inflateNote(inflateLevel);
+ }
+
+ @Override
+ protected DataKind inflateWebsite(int inflateLevel) {
+ return super.inflateWebsite(inflateLevel);
+ }
+
+ // TODO: this should come from resource in the future
+ // Note that frameworks/base/core/java/android/pim/vcard/ContactStruct.java also wants
+ // this String.
+ private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts";
+
+ public static final void attemptMyContactsMembership(EntityDelta state, Context context) {
+ final ValuesDelta stateValues = state.getValues();
+ stateValues.setFromTemplate(true);
+ final String accountName = stateValues.getAsString(RawContacts.ACCOUNT_NAME);
+ final String accountType = stateValues.getAsString(RawContacts.ACCOUNT_TYPE);
+ attemptMyContactsMembership(state, accountName, accountType, context, true);
+ }
+
+ public static final void createMyContactsIfNotExist(Account account, Context context) {
+ attemptMyContactsMembership(null, account.name, account.type, context, true);
+ }
+
+ /**
+ *
+ * @param allowRecur If the group is created between querying/about to create, we recur. But
+ * to prevent excess recursion, we provide a flag to make sure we only do the recursion loop
+ * once
+ */
+ private static final void attemptMyContactsMembership(EntityDelta state,
+ final String accountName, final String accountType, Context context,
+ boolean allowRecur) {
+ final ContentResolver resolver = context.getContentResolver();
+
+ Cursor cursor = resolver.query(Groups.CONTENT_URI,
+ new String[] {Groups.TITLE, Groups.SOURCE_ID, Groups.SHOULD_SYNC},
+ Groups.ACCOUNT_NAME + " =? AND " + Groups.ACCOUNT_TYPE + " =?",
+ new String[] {accountName, accountType}, null);
+
+ boolean myContactsExists = false;
+ long assignToGroupSourceId = -1;
+ while (cursor.moveToNext()) {
+ if (GOOGLE_MY_CONTACTS_GROUP.equals(cursor.getString(0))) {
+ myContactsExists = true;
+ }
+ if (assignToGroupSourceId == -1 && cursor.getInt(2) != 0) {
+ assignToGroupSourceId = cursor.getInt(1);
+ }
+
+ if (myContactsExists && assignToGroupSourceId != -1) {
+ break;
+ }
+ }
+
+ if (myContactsExists && state == null) {
+ return;
+ }
+
+ try {
+ final ContentValues values = new ContentValues();
+ values.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
+
+ if (!myContactsExists) {
+ // create the group if it doesn't exist
+ final ContentValues newGroup = new ContentValues();
+ newGroup.put(Groups.TITLE, GOOGLE_MY_CONTACTS_GROUP);
+
+ newGroup.put(Groups.ACCOUNT_NAME, accountName);
+ newGroup.put(Groups.ACCOUNT_TYPE, accountType);
+ newGroup.put(Groups.GROUP_VISIBLE, "1");
+
+ ArrayList<ContentProviderOperation> operations =
+ new ArrayList<ContentProviderOperation>();
+
+ operations.add(ContentProviderOperation
+ .newAssertQuery(Groups.CONTENT_URI)
+ .withSelection(Groups.TITLE + "=?",
+ new String[] { GOOGLE_MY_CONTACTS_GROUP })
+ .withExpectedCount(0).build());
+ operations.add(ContentProviderOperation
+
+ .newInsert(Groups.CONTENT_URI)
+ .withValues(newGroup)
+ .build());
+ try {
+ ContentProviderResult[] results = resolver.applyBatch(
+ ContactsContract.AUTHORITY, operations);
+ values.put(GroupMembership.GROUP_ROW_ID, ContentUris.parseId(results[1].uri));
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Problem querying for groups", e);
+ } catch (OperationApplicationException e) {
+ // the group was created after the query but before we tried to create it
+ if (allowRecur) {
+ attemptMyContactsMembership(
+ state, accountName, accountType, context, false);
+ }
+ return;
+ }
+ } else {
+ if (assignToGroupSourceId != -1) {
+ values.put(GroupMembership.GROUP_SOURCE_ID, assignToGroupSourceId);
+ } else {
+ // there are no Groups to add this contact to, so don't apply any membership
+ // TODO: alert user that their contact will be dropped?
+ }
+ }
+ if (state != null) {
+ state.addEntry(ValuesDelta.fromAfter(values));
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ @Override
+ public int getHeaderColor(Context context) {
+ return 0xff89c2c2;
+ }
+
+ @Override
+ public int getSideBarColor(Context context) {
+ return 0xff5bb4b4;
+ }
+}
diff --git a/src/com/android/contacts/model/Sources.java b/src/com/android/contacts/model/Sources.java
new file mode 100644
index 0000000..f664fb1
--- /dev/null
+++ b/src/com/android/contacts/model/Sources.java
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.model;
+
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+import com.google.android.collect.Sets;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorDescription;
+import android.accounts.OnAccountsUpdateListener;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentService;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SyncAdapterType;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * Singleton holder for all parsed {@link ContactsSource} available on the
+ * system, typically filled through {@link PackageManager} queries.
+ */
+public class Sources extends BroadcastReceiver implements OnAccountsUpdateListener {
+ private static final String TAG = "Sources";
+
+ private Context mApplicationContext;
+ private AccountManager mAccountManager;
+
+ private ContactsSource mFallbackSource = null;
+
+ private HashMap<String, ContactsSource> mSources = Maps.newHashMap();
+ private HashSet<String> mKnownPackages = Sets.newHashSet();
+
+ private static SoftReference<Sources> sInstance = null;
+
+ /**
+ * Requests the singleton instance of {@link Sources} with data bound from
+ * the available authenticators. This method blocks until its interaction
+ * with {@link AccountManager} is finished, so don't call from a UI thread.
+ */
+ public static synchronized Sources getInstance(Context context) {
+ Sources sources = sInstance == null ? null : sInstance.get();
+ if (sources == null) {
+ sources = new Sources(context);
+ sInstance = new SoftReference<Sources>(sources);
+ }
+ return sources;
+ }
+
+ /**
+ * Internal constructor that only performs initial parsing.
+ */
+ private Sources(Context context) {
+ mApplicationContext = context.getApplicationContext();
+ mAccountManager = AccountManager.get(mApplicationContext);
+
+ // Create fallback contacts source for on-phone contacts
+ mFallbackSource = new FallbackSource();
+
+ queryAccounts();
+
+ // Request updates when packages or accounts change
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addDataScheme("package");
+
+ mApplicationContext.registerReceiver(this, filter);
+ mAccountManager.addOnAccountsUpdatedListener(this, null, false);
+ }
+
+ /** @hide exposed for unit tests */
+ public Sources(ContactsSource... sources) {
+ for (ContactsSource source : sources) {
+ addSource(source);
+ }
+ }
+
+ protected void addSource(ContactsSource source) {
+ mSources.put(source.accountType, source);
+ mKnownPackages.add(source.resPackageName);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final String packageName = intent.getData().getSchemeSpecificPart();
+
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
+ || Intent.ACTION_PACKAGE_ADDED.equals(action)
+ || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ final boolean knownPackage = mKnownPackages.contains(packageName);
+ if (knownPackage) {
+ // Invalidate cache of existing source
+ invalidateCache(packageName);
+ } else {
+ // Unknown source, so reload from scratch
+ queryAccounts();
+ }
+ }
+ }
+
+ protected void invalidateCache(String packageName) {
+ for (ContactsSource source : mSources.values()) {
+ if (TextUtils.equals(packageName, source.resPackageName)) {
+ // Invalidate any cache for the changed package
+ source.invalidateCache();
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void onAccountsUpdated(Account[] accounts) {
+ // Refresh to catch any changed accounts
+ queryAccounts();
+ }
+
+ /**
+ * Blocking call to load all {@link AuthenticatorDescription} known by the
+ * {@link AccountManager} on the system.
+ */
+ protected synchronized void queryAccounts() {
+ mSources.clear();
+ mKnownPackages.clear();
+
+ final AccountManager am = mAccountManager;
+ final IContentService cs = ContentResolver.getContentService();
+
+ try {
+ final SyncAdapterType[] syncs = cs.getSyncAdapterTypes();
+ final AuthenticatorDescription[] auths = am.getAuthenticatorTypes();
+
+ for (SyncAdapterType sync : syncs) {
+ if (!ContactsContract.AUTHORITY.equals(sync.authority)) {
+ // Skip sync adapters that don't provide contact data.
+ continue;
+ }
+
+ // Look for the formatting details provided by each sync
+ // adapter, using the authenticator to find general resources.
+ final String accountType = sync.accountType;
+ final AuthenticatorDescription auth = findAuthenticator(auths, accountType);
+
+ ContactsSource source;
+ if (GoogleSource.ACCOUNT_TYPE.equals(accountType)) {
+ source = new GoogleSource(auth.packageName);
+ } else if (ExchangeSource.ACCOUNT_TYPE.equals(accountType)) {
+ source = new ExchangeSource(auth.packageName);
+ } else {
+ // TODO: use syncadapter package instead, since it provides resources
+ Log.d(TAG, "Creating external source for type=" + accountType
+ + ", packageName=" + auth.packageName);
+ source = new ExternalSource(auth.packageName);
+ source.readOnly = !sync.supportsUploading();
+ }
+
+ source.accountType = auth.type;
+ source.titleRes = auth.labelId;
+ source.iconRes = auth.iconId;
+
+ addSource(source);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Problem loading accounts: " + e.toString());
+ }
+ }
+
+ /**
+ * Find a specific {@link AuthenticatorDescription} in the provided list
+ * that matches the given account type.
+ */
+ protected static AuthenticatorDescription findAuthenticator(AuthenticatorDescription[] auths,
+ String accountType) {
+ for (AuthenticatorDescription auth : auths) {
+ if (accountType.equals(auth.type)) {
+ return auth;
+ }
+ }
+ throw new IllegalStateException("Couldn't find authenticator for specific account type");
+ }
+
+ /**
+ * Return list of all known, writable {@link ContactsSource}. Sources
+ * returned may require inflation before they can be used.
+ */
+ public ArrayList<Account> getAccounts(boolean writableOnly) {
+ final AccountManager am = mAccountManager;
+ final Account[] accounts = am.getAccounts();
+ final ArrayList<Account> matching = Lists.newArrayList();
+
+ for (Account account : accounts) {
+ // Ensure we have details loaded for each account
+ final ContactsSource source = getInflatedSource(account.type,
+ ContactsSource.LEVEL_SUMMARY);
+ final boolean hasContacts = source != null;
+ final boolean matchesWritable = (!writableOnly || (writableOnly && !source.readOnly));
+ if (hasContacts && matchesWritable) {
+ matching.add(account);
+ }
+ }
+ return matching;
+ }
+
+ /**
+ * Find the best {@link DataKind} matching the requested
+ * {@link ContactsSource#accountType} and {@link DataKind#mimeType}. If no
+ * direct match found, we try searching {@link #mFallbackSource}.
+ */
+ public DataKind getKindOrFallback(String accountType, String mimeType, Context context,
+ int inflateLevel) {
+ DataKind kind = null;
+
+ // Try finding source and kind matching request
+ final ContactsSource source = mSources.get(accountType);
+ if (source != null) {
+ source.ensureInflated(context, inflateLevel);
+ kind = source.getKindForMimetype(mimeType);
+ }
+
+ if (kind == null) {
+ // Nothing found, so try fallback as last resort
+ mFallbackSource.ensureInflated(context, inflateLevel);
+ kind = mFallbackSource.getKindForMimetype(mimeType);
+ }
+
+ if (kind == null) {
+ Log.w(TAG, "Unknown type=" + accountType + ", mime=" + mimeType);
+ }
+
+ return kind;
+ }
+
+ /**
+ * Return {@link ContactsSource} for the given account type.
+ */
+ public ContactsSource getInflatedSource(String accountType, int inflateLevel) {
+ // Try finding specific source, otherwise use fallback
+ ContactsSource source = mSources.get(accountType);
+ if (source == null) source = mFallbackSource;
+
+ if (source.isInflated(inflateLevel)) {
+ // Already inflated, so return directly
+ return source;
+ } else {
+ // Not inflated, but requested that we force-inflate
+ source.ensureInflated(mApplicationContext, inflateLevel);
+ return source;
+ }
+ }
+}
diff --git a/src/com/android/contacts/ui/DisplayGroupsActivity.java b/src/com/android/contacts/ui/DisplayGroupsActivity.java
new file mode 100644
index 0000000..ce68dcb
--- /dev/null
+++ b/src/com/android/contacts/ui/DisplayGroupsActivity.java
@@ -0,0 +1,860 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui;
+
+import com.android.contacts.R;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.GoogleSource;
+import com.android.contacts.model.Sources;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.util.EmptyService;
+import com.android.contacts.util.WeakAsyncTask;
+import com.google.android.collect.Lists;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ExpandableListActivity;
+import android.app.ProgressDialog;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.EntityIterator;
+import android.content.Intent;
+import android.content.OperationApplicationException;
+import android.content.SharedPreferences;
+import android.content.ContentProviderOperation.Builder;
+import android.content.SharedPreferences.Editor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.preference.PreferenceManager;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Groups;
+import android.provider.ContactsContract.Settings;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.widget.AdapterView;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.CheckBox;
+import android.widget.ExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.TextView;
+import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+
+/**
+ * Shows a list of all available {@link Groups} available, letting the user
+ * select which ones they want to be visible.
+ */
+public final class DisplayGroupsActivity extends ExpandableListActivity implements
+ AdapterView.OnItemClickListener, View.OnClickListener {
+ private static final String TAG = "DisplayGroupsActivity";
+
+ public interface Prefs {
+ public static final String DISPLAY_ONLY_PHONES = "only_phones";
+ public static final boolean DISPLAY_ONLY_PHONES_DEFAULT = false;
+
+ }
+
+ private ExpandableListView mList;
+ private DisplayAdapter mAdapter;
+
+ private SharedPreferences mPrefs;
+
+ private CheckBox mDisplayPhones;
+
+ private View mHeaderPhones;
+ private View mHeaderSeparator;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.act_display_groups);
+
+ mList = getExpandableListView();
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+
+ final LayoutInflater inflater = getLayoutInflater();
+
+ // Add the "Only contacts with phones" header modifier.
+ mHeaderPhones = inflater.inflate(R.layout.display_header, mList, false);
+ mHeaderPhones.setId(R.id.header_phones);
+ mDisplayPhones = (CheckBox) mHeaderPhones.findViewById(android.R.id.checkbox);
+ mDisplayPhones.setChecked(mPrefs.getBoolean(Prefs.DISPLAY_ONLY_PHONES,
+ Prefs.DISPLAY_ONLY_PHONES_DEFAULT));
+ {
+ final TextView text1 = (TextView)mHeaderPhones.findViewById(android.R.id.text1);
+ final TextView text2 = (TextView)mHeaderPhones.findViewById(android.R.id.text2);
+ text1.setText(R.string.showFilterPhones);
+ text2.setText(R.string.showFilterPhonesDescrip);
+ }
+ mList.addHeaderView(mHeaderPhones, null, true);
+
+ // Add the separator before showing the detailed group list.
+ mHeaderSeparator = inflater.inflate(R.layout.list_separator, mList, false);
+ {
+ final TextView text1 = (TextView)mHeaderSeparator;
+ text1.setText(R.string.headerContactGroups);
+ }
+ mList.addHeaderView(mHeaderSeparator, null, false);
+
+ findViewById(R.id.btn_done).setOnClickListener(this);
+ findViewById(R.id.btn_discard).setOnClickListener(this);
+
+ // Catch clicks on the header views
+ mList.setOnItemClickListener(this);
+ mList.setOnCreateContextMenuListener(this);
+
+ // Start background query to find account details
+ new QueryGroupsTask(this).execute();
+ }
+
+ /**
+ * Background operation to build set of {@link AccountDisplay} for each
+ * {@link Sources#getAccounts(boolean)} that provides groups.
+ */
+ private static class QueryGroupsTask extends
+ WeakAsyncTask<Void, Void, AccountSet, DisplayGroupsActivity> {
+ public QueryGroupsTask(DisplayGroupsActivity target) {
+ super(target);
+ }
+
+ @Override
+ protected AccountSet doInBackground(DisplayGroupsActivity target,
+ Void... params) {
+ final Context context = target;
+ final Sources sources = Sources.getInstance(context);
+ final ContentResolver resolver = context.getContentResolver();
+
+ // Inflate groups entry for each account
+ final AccountSet accounts = new AccountSet();
+ for (Account account : sources.getAccounts(false)) {
+ accounts.add(new AccountDisplay(resolver, account.name, account.type));
+ }
+
+ return accounts;
+ }
+
+ @Override
+ protected void onPostExecute(DisplayGroupsActivity target, AccountSet result) {
+ // Build adapter to show available groups
+ final Context context = target;
+ final DisplayAdapter adapter = new DisplayAdapter(context, result);
+ target.setListAdapter(adapter);
+ }
+ }
+
+ public void setListAdapter(DisplayAdapter adapter) {
+ mAdapter = adapter;
+ mAdapter.setChildDescripWithPhones(mDisplayPhones.isChecked());
+ super.setListAdapter(mAdapter);
+ }
+
+ private static final int DEFAULT_SHOULD_SYNC = 1;
+ private static final int DEFAULT_VISIBLE = 0;
+
+ /**
+ * Entry holding any changes to {@link Groups} or {@link Settings} rows,
+ * such as {@link Groups#SHOULD_SYNC} or {@link Groups#GROUP_VISIBLE}.
+ */
+ protected static class GroupDelta extends ValuesDelta {
+ private boolean mUngrouped = false;
+ private boolean mAccountHasGroups;
+
+ private GroupDelta() {
+ super();
+ }
+
+ /**
+ * Build {@link GroupDelta} from the {@link Settings} row for the given
+ * {@link Settings#ACCOUNT_NAME} and {@link Settings#ACCOUNT_TYPE}.
+ */
+ public static GroupDelta fromSettings(ContentResolver resolver, String accountName,
+ String accountType, boolean accountHasGroups) {
+ final Uri settingsUri = Settings.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Settings.ACCOUNT_NAME, accountName)
+ .appendQueryParameter(Settings.ACCOUNT_TYPE, accountType).build();
+ final Cursor cursor = resolver.query(settingsUri, new String[] {
+ Settings.SHOULD_SYNC, Settings.UNGROUPED_VISIBLE
+ }, null, null, null);
+
+ try {
+ final ContentValues values = new ContentValues();
+ values.put(Settings.ACCOUNT_NAME, accountName);
+ values.put(Settings.ACCOUNT_TYPE, accountType);
+
+ if (cursor != null && cursor.moveToFirst()) {
+ // Read existing values when present
+ values.put(Settings.SHOULD_SYNC, cursor.getInt(0));
+ values.put(Settings.UNGROUPED_VISIBLE, cursor.getInt(1));
+ return fromBefore(values).setUngrouped(accountHasGroups);
+ } else {
+ // Nothing found, so treat as create
+ values.put(Settings.SHOULD_SYNC, DEFAULT_SHOULD_SYNC);
+ values.put(Settings.UNGROUPED_VISIBLE, DEFAULT_VISIBLE);
+ return fromAfter(values).setUngrouped(accountHasGroups);
+ }
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+
+ public static GroupDelta fromBefore(ContentValues before) {
+ final GroupDelta entry = new GroupDelta();
+ entry.mBefore = before;
+ entry.mAfter = new ContentValues();
+ return entry;
+ }
+
+ public static GroupDelta fromAfter(ContentValues after) {
+ final GroupDelta entry = new GroupDelta();
+ entry.mBefore = null;
+ entry.mAfter = after;
+ return entry;
+ }
+
+ protected GroupDelta setUngrouped(boolean accountHasGroups) {
+ mUngrouped = true;
+ mAccountHasGroups = accountHasGroups;
+ return this;
+ }
+
+ @Override
+ public boolean beforeExists() {
+ return mBefore != null;
+ }
+
+ public boolean getShouldSync() {
+ return getAsInteger(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC,
+ DEFAULT_SHOULD_SYNC) != 0;
+ }
+
+ public boolean getVisible() {
+ return getAsInteger(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE,
+ DEFAULT_VISIBLE) != 0;
+ }
+
+ public void putShouldSync(boolean shouldSync) {
+ put(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC, shouldSync ? 1 : 0);
+ }
+
+ public void putVisible(boolean visible) {
+ put(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE, visible ? 1 : 0);
+ }
+
+ public CharSequence getTitle(Context context) {
+ if (mUngrouped) {
+ if (mAccountHasGroups) {
+ return context.getText(R.string.display_ungrouped);
+ } else {
+ return context.getText(R.string.display_all_contacts);
+ }
+ } else {
+ final Integer titleRes = getAsInteger(Groups.TITLE_RES);
+ if (titleRes != null) {
+ final String packageName = getAsString(Groups.RES_PACKAGE);
+ return context.getPackageManager().getText(packageName, titleRes, null);
+ } else {
+ return getAsString(Groups.TITLE);
+ }
+ }
+ }
+
+ /**
+ * Build a possible {@link ContentProviderOperation} to persist any
+ * changes to the {@link Groups} or {@link Settings} row described by
+ * this {@link GroupDelta}.
+ */
+ public ContentProviderOperation buildDiff() {
+ if (isNoop()) {
+ return null;
+ } else if (isUpdate()) {
+ // When has changes and "before" exists, then "update"
+ final Builder builder = ContentProviderOperation
+ .newUpdate(mUngrouped ? Settings.CONTENT_URI : addCallerIsSyncAdapterParameter(Groups.CONTENT_URI));
+ if (mUngrouped) {
+ builder.withSelection(Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE
+ + "=?", new String[] {
+ this.getAsString(Settings.ACCOUNT_NAME),
+ this.getAsString(Settings.ACCOUNT_TYPE)
+ });
+ } else {
+ builder.withSelection(Groups._ID + "=" + this.getId(), null);
+ }
+ builder.withValues(mAfter);
+ return builder.build();
+ } else if (isInsert() && mUngrouped) {
+ // Only allow inserts for Settings
+ mAfter.remove(mIdColumn);
+ final Builder builder = ContentProviderOperation.newInsert(Settings.CONTENT_URI);
+ builder.withValues(mAfter);
+ return builder.build();
+ } else {
+ throw new IllegalStateException("Unexpected delete or insert");
+ }
+ }
+ }
+
+ private static Uri addCallerIsSyncAdapterParameter(Uri uri) {
+ return uri.buildUpon()
+ .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
+ .build();
+ }
+
+ /**
+ * {@link Comparator} to sort by {@link Groups#_ID}.
+ */
+ private static Comparator<GroupDelta> sIdComparator = new Comparator<GroupDelta>() {
+ public int compare(GroupDelta object1, GroupDelta object2) {
+ return object1.getViewId() - object2.getViewId();
+ }
+ };
+
+ /**
+ * Set of all {@link AccountDisplay} entries, one for each source.
+ */
+ protected static class AccountSet extends ArrayList<AccountDisplay> {
+ public ArrayList<ContentProviderOperation> buildDiff() {
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ for (AccountDisplay account : this) {
+ account.buildDiff(diff);
+ }
+ return diff;
+ }
+ }
+
+ /**
+ * {@link GroupDelta} details for a single {@link Account}, usually shown as
+ * children under a single expandable group.
+ */
+ protected static class AccountDisplay {
+ public String mName;
+ public String mType;
+
+ public GroupDelta mUngrouped;
+ public ArrayList<GroupDelta> mSyncedGroups = Lists.newArrayList();
+ public ArrayList<GroupDelta> mUnsyncedGroups = Lists.newArrayList();
+
+ /**
+ * Build an {@link AccountDisplay} covering all {@link Groups} under the
+ * given {@link Account}.
+ */
+ public AccountDisplay(ContentResolver resolver, String accountName, String accountType) {
+ mName = accountName;
+ mType = accountType;
+
+ boolean hasGroups = false;
+
+ final Uri groupsUri = Groups.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Groups.ACCOUNT_NAME, accountName)
+ .appendQueryParameter(Groups.ACCOUNT_TYPE, accountType).build();
+ EntityIterator iterator = null;
+ try {
+ // Create entries for each known group
+ iterator = resolver.queryEntities(groupsUri, null, null, null);
+ while (iterator.hasNext()) {
+ final ContentValues values = iterator.next().getEntityValues();
+ final GroupDelta group = GroupDelta.fromBefore(values);
+ addGroup(group);
+ hasGroups = true;
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Problem reading groups: " + e.toString());
+ } finally {
+ if (iterator != null) iterator.close();
+ }
+
+ // Create single entry handling ungrouped status
+ mUngrouped = GroupDelta.fromSettings(resolver, accountName, accountType, hasGroups);
+ addGroup(mUngrouped);
+ }
+
+ /**
+ * Add the given {@link GroupDelta} internally, filing based on its
+ * {@link GroupDelta#getShouldSync()} status.
+ */
+ private void addGroup(GroupDelta group) {
+ if (group.getShouldSync()) {
+ mSyncedGroups.add(group);
+ } else {
+ mUnsyncedGroups.add(group);
+ }
+ }
+
+ /**
+ * Set the {@link GroupDelta#putShouldSync(boolean)} value for all
+ * children {@link GroupDelta} rows.
+ */
+ public void setShouldSync(boolean shouldSync) {
+ final Iterator<GroupDelta> oppositeChildren = shouldSync ?
+ mUnsyncedGroups.iterator() : mSyncedGroups.iterator();
+ while (oppositeChildren.hasNext()) {
+ final GroupDelta child = oppositeChildren.next();
+ setShouldSync(child, shouldSync, false);
+ oppositeChildren.remove();
+ }
+ }
+
+ public void setShouldSync(GroupDelta child, boolean shouldSync) {
+ setShouldSync(child, shouldSync, true);
+ }
+
+ /**
+ * Set {@link GroupDelta#putShouldSync(boolean)}, and file internally
+ * based on updated state.
+ */
+ public void setShouldSync(GroupDelta child, boolean shouldSync, boolean attemptRemove) {
+ child.putShouldSync(shouldSync);
+ if (shouldSync) {
+ if (attemptRemove) {
+ mUnsyncedGroups.remove(child);
+ }
+ mSyncedGroups.add(child);
+ Collections.sort(mSyncedGroups, sIdComparator);
+ } else {
+ if (attemptRemove) {
+ mSyncedGroups.remove(child);
+ }
+ mUnsyncedGroups.add(child);
+ }
+ }
+
+ /**
+ * Build set of {@link ContentProviderOperation} to persist any user
+ * changes to {@link GroupDelta} rows under this {@link Account}.
+ */
+ public void buildDiff(ArrayList<ContentProviderOperation> diff) {
+ for (GroupDelta group : mSyncedGroups) {
+ final ContentProviderOperation oper = group.buildDiff();
+ if (oper != null) diff.add(oper);
+ }
+ for (GroupDelta group : mUnsyncedGroups) {
+ final ContentProviderOperation oper = group.buildDiff();
+ if (oper != null) diff.add(oper);
+ }
+ }
+ }
+
+ /**
+ * {@link ExpandableListAdapter} that shows {@link GroupDelta} settings,
+ * grouped by {@link Account} source. Shows footer row when any groups are
+ * unsynced, as determined through {@link AccountDisplay#mUnsyncedGroups}.
+ */
+ protected static class DisplayAdapter extends BaseExpandableListAdapter {
+ private Context mContext;
+ private LayoutInflater mInflater;
+ private Sources mSources;
+
+ private AccountSet mAccounts;
+
+ private boolean mChildWithPhones = false;
+
+ public DisplayAdapter(Context context, AccountSet accounts) {
+ mContext = context;
+ mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mSources = Sources.getInstance(context);
+
+ mAccounts = accounts;
+ }
+
+ /**
+ * In group descriptions, show the number of contacts with phone
+ * numbers, in addition to the total contacts.
+ */
+ public void setChildDescripWithPhones(boolean withPhones) {
+ mChildWithPhones = withPhones;
+ }
+
+ /** {@inheritDoc} */
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+ View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.display_child, parent, false);
+ }
+
+ final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
+ final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
+ final CheckBox checkbox = (CheckBox)convertView.findViewById(android.R.id.checkbox);
+
+ final AccountDisplay account = mAccounts.get(groupPosition);
+ final GroupDelta child = (GroupDelta)this.getChild(groupPosition, childPosition);
+ if (child != null) {
+ // Handle normal group, with title and checkbox
+ final boolean groupVisible = child.getVisible();
+ checkbox.setVisibility(View.VISIBLE);
+ checkbox.setChecked(groupVisible);
+
+ final CharSequence groupTitle = child.getTitle(mContext);
+ text1.setText(groupTitle);
+
+// final int count = cursor.getInt(GroupsQuery.SUMMARY_COUNT);
+// final int withPhones = cursor.getInt(GroupsQuery.SUMMARY_WITH_PHONES);
+
+// final CharSequence descrip = mContext.getResources().getQuantityString(
+// mChildWithPhones ? R.plurals.groupDescripPhones : R.plurals.groupDescrip,
+// count, count, withPhones);
+
+// text2.setText(descrip);
+ text2.setVisibility(View.GONE);
+ } else {
+ // When unknown child, this is "more" footer view
+ checkbox.setVisibility(View.GONE);
+ text1.setText(R.string.display_more_groups);
+ text2.setVisibility(View.GONE);
+ }
+
+ return convertView;
+ }
+
+ /** {@inheritDoc} */
+ public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+ ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.display_group, parent, false);
+ }
+
+ final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
+ final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
+
+ final AccountDisplay account = (AccountDisplay)this.getGroup(groupPosition);
+
+ final ContactsSource source = mSources.getInflatedSource(account.mType,
+ ContactsSource.LEVEL_SUMMARY);
+
+ text1.setText(account.mName);
+ text2.setText(source.getDisplayLabel(mContext));
+ text2.setVisibility(account.mName == null ? View.GONE : View.VISIBLE);
+
+ return convertView;
+ }
+
+ /** {@inheritDoc} */
+ public Object getChild(int groupPosition, int childPosition) {
+ final AccountDisplay account = mAccounts.get(groupPosition);
+ final boolean validChild = childPosition >= 0
+ && childPosition < account.mSyncedGroups.size();
+ if (validChild) {
+ return account.mSyncedGroups.get(childPosition);
+ } else {
+ return null;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public long getChildId(int groupPosition, int childPosition) {
+ final GroupDelta child = (GroupDelta)getChild(groupPosition, childPosition);
+ if (child != null) {
+ final Long childId = child.getId();
+ return childId != null ? childId : Long.MIN_VALUE;
+ } else {
+ return Long.MIN_VALUE;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public int getChildrenCount(int groupPosition) {
+ // Count is any synced groups, plus possible footer
+ final AccountDisplay account = mAccounts.get(groupPosition);
+ final boolean anyHidden = account.mUnsyncedGroups.size() > 0;
+ return account.mSyncedGroups.size() + (anyHidden ? 1 : 0);
+ }
+
+ /** {@inheritDoc} */
+ public Object getGroup(int groupPosition) {
+ return mAccounts.get(groupPosition);
+ }
+
+ /** {@inheritDoc} */
+ public int getGroupCount() {
+ return mAccounts.size();
+ }
+
+ /** {@inheritDoc} */
+ public long getGroupId(int groupPosition) {
+ return groupPosition;
+ }
+
+ /** {@inheritDoc} */
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
+ }
+ }
+
+ /**
+ * Handle any clicks on header views added to our {@link #mAdapter}, which
+ * are usually the global modifier checkboxes.
+ */
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ switch (view.getId()) {
+ case R.id.header_phones: {
+ mDisplayPhones.toggle();
+ break;
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.btn_done: {
+ this.doSaveAction();
+ break;
+ }
+ case R.id.btn_discard: {
+ this.finish();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Assign a specific value to {@link Prefs#DISPLAY_ONLY_PHONES}, refreshing
+ * the visible list as needed.
+ */
+ protected void setDisplayOnlyPhones(boolean displayOnlyPhones) {
+ mDisplayPhones.setChecked(displayOnlyPhones);
+
+ Editor editor = mPrefs.edit();
+ editor.putBoolean(Prefs.DISPLAY_ONLY_PHONES, displayOnlyPhones);
+ editor.commit();
+
+ mAdapter.setChildDescripWithPhones(displayOnlyPhones);
+ mAdapter.notifyDataSetChanged();
+ }
+
+ /**
+ * Handle any clicks on {@link ExpandableListAdapter} children, which
+ * usually mean toggling its visible state.
+ */
+ @Override
+ public boolean onChildClick(ExpandableListView parent, View view, int groupPosition,
+ int childPosition, long id) {
+ final CheckBox checkbox = (CheckBox)view.findViewById(android.R.id.checkbox);
+
+ final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition);
+ final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition);
+ if (child != null) {
+ checkbox.toggle();
+ child.putVisible(checkbox.isChecked());
+ } else {
+ // Open context menu for bringing back unsynced
+ this.openContextMenu(view);
+ }
+ return true;
+ }
+
+ // TODO: move these definitions to framework constants when we begin
+ // defining this mode through <sync-adapter> tags
+ private static final int SYNC_MODE_UNSUPPORTED = 0;
+ private static final int SYNC_MODE_UNGROUPED = 1;
+ private static final int SYNC_MODE_EVERYTHING = 2;
+
+ protected int getSyncMode(AccountDisplay account) {
+ // TODO: read sync mode through <sync-adapter> definition
+ if (GoogleSource.ACCOUNT_TYPE.equals(account.mType)) {
+ return SYNC_MODE_EVERYTHING;
+ } else {
+ return SYNC_MODE_UNSUPPORTED;
+ }
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view,
+ ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+
+ // Bail if not working with expandable long-press, or if not child
+ if (!(menuInfo instanceof ExpandableListContextMenuInfo)) return;
+
+ final ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuInfo;
+ final int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
+ final int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);
+
+ // Skip long-press on expandable parents
+ if (childPosition == -1) return;
+
+ final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition);
+ final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition);
+
+ // Ignore when selective syncing unsupported
+ final int syncMode = getSyncMode(account);
+ if (syncMode == SYNC_MODE_UNSUPPORTED) return;
+
+ if (child != null) {
+ showRemoveSync(menu, account, child, syncMode);
+ } else {
+ showAddSync(menu, account, syncMode);
+ }
+ }
+
+ protected void showRemoveSync(ContextMenu menu, final AccountDisplay account,
+ final GroupDelta child, final int syncMode) {
+ final CharSequence title = child.getTitle(this);
+
+ menu.setHeaderTitle(title);
+ menu.add(R.string.menu_sync_remove).setOnMenuItemClickListener(
+ new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ handleRemoveSync(account, child, syncMode, title);
+ return true;
+ }
+ });
+ }
+
+ protected void handleRemoveSync(final AccountDisplay account, final GroupDelta child,
+ final int syncMode, CharSequence title) {
+ final boolean shouldSyncUngrouped = account.mUngrouped.getShouldSync();
+ if (syncMode == SYNC_MODE_EVERYTHING && shouldSyncUngrouped
+ && !child.equals(account.mUngrouped)) {
+ // Warn before removing this group when it would cause ungrouped to stop syncing
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ final CharSequence removeMessage = this.getString(
+ R.string.display_warn_remove_ungrouped, title);
+ builder.setTitle(R.string.menu_sync_remove);
+ builder.setMessage(removeMessage);
+ builder.setNegativeButton(android.R.string.cancel, null);
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Mark both this group and ungrouped to stop syncing
+ account.setShouldSync(account.mUngrouped, false);
+ account.setShouldSync(child, false);
+ mAdapter.notifyDataSetChanged();
+ }
+ });
+ builder.show();
+ } else {
+ // Mark this group to not sync
+ account.setShouldSync(child, false);
+ mAdapter.notifyDataSetChanged();
+ }
+ }
+
+ protected void showAddSync(ContextMenu menu, final AccountDisplay account, final int syncMode) {
+ menu.setHeaderTitle(R.string.dialog_sync_add);
+
+ // Create item for each available, unsynced group
+ for (final GroupDelta child : account.mUnsyncedGroups) {
+ if (!child.getShouldSync()) {
+ final CharSequence title = child.getTitle(this);
+ menu.add(title).setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ // Adding specific group for syncing
+ if (child.mUngrouped && syncMode == SYNC_MODE_EVERYTHING) {
+ account.setShouldSync(true);
+ } else {
+ account.setShouldSync(child, true);
+ }
+ mAdapter.notifyDataSetChanged();
+ return true;
+ }
+ });
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onBackPressed() {
+ doSaveAction();
+ }
+
+ private void doSaveAction() {
+ if (mAdapter == null) return;
+ setDisplayOnlyPhones(mDisplayPhones.isChecked());
+ new UpdateTask(this).execute(mAdapter.mAccounts);
+ }
+
+ /**
+ * Background task that persists changes to {@link Groups#GROUP_VISIBLE},
+ * showing spinner dialog to user while updating.
+ */
+ public static class UpdateTask extends
+ WeakAsyncTask<AccountSet, Void, Void, Activity> {
+ private WeakReference<ProgressDialog> mProgress;
+
+ public UpdateTask(Activity target) {
+ super(target);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onPreExecute(Activity target) {
+ final Context context = target;
+
+ mProgress = new WeakReference<ProgressDialog>(ProgressDialog.show(context, null,
+ context.getText(R.string.savingDisplayGroups)));
+
+ // Before starting this task, start an empty service to protect our
+ // process from being reclaimed by the system.
+ context.startService(new Intent(context, EmptyService.class));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected Void doInBackground(Activity target, AccountSet... params) {
+ final Context context = target;
+ final ContentValues values = new ContentValues();
+ final ContentResolver resolver = context.getContentResolver();
+
+ try {
+ // Build changes and persist in transaction
+ final AccountSet set = params[0];
+ final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+ resolver.applyBatch(ContactsContract.AUTHORITY, diff);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Problem saving display groups", e);
+ } catch (OperationApplicationException e) {
+ Log.e(TAG, "Problem saving display groups", e);
+ }
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onPostExecute(Activity target, Void result) {
+ final Context context = target;
+
+ final ProgressDialog dialog = mProgress.get();
+ if (dialog != null) dialog.dismiss();
+
+ target.finish();
+
+ // Stop the service that was protecting us
+ context.stopService(new Intent(context, EmptyService.class));
+ }
+ }
+}
diff --git a/src/com/android/contacts/ui/EditContactActivity.java b/src/com/android/contacts/ui/EditContactActivity.java
new file mode 100644
index 0000000..914a2e8
--- /dev/null
+++ b/src/com/android/contacts/ui/EditContactActivity.java
@@ -0,0 +1,1253 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui;
+
+import com.android.contacts.ContactsListActivity;
+import com.android.contacts.ContactsUtils;
+import com.android.contacts.R;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.Editor;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.EntitySet;
+import com.android.contacts.model.GoogleSource;
+import com.android.contacts.model.Sources;
+import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.Editor.EditorListener;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.ui.widget.BaseContactEditorView;
+import com.android.contacts.ui.widget.PhotoEditorView;
+import com.android.contacts.util.EmptyService;
+import com.android.contacts.util.WeakAsyncTask;
+import com.google.android.collect.Lists;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.ActivityNotFoundException;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Entity;
+import android.content.Intent;
+import android.content.OperationApplicationException;
+import android.content.ContentProviderOperation.Builder;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.AggregationExceptions;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Contacts.Data;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+/**
+ * Activity for editing or inserting a contact.
+ */
+public final class EditContactActivity extends Activity
+ implements View.OnClickListener, Comparator<EntityDelta> {
+ private static final String TAG = "EditContactActivity";
+
+ /** The launch code when picking a photo and the raw data is returned */
+ private static final int PHOTO_PICKED_WITH_DATA = 3021;
+
+ /** The launch code when a contact to join with is returned */
+ private static final int REQUEST_JOIN_CONTACT = 3022;
+
+ private static final String KEY_EDIT_STATE = "state";
+ private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
+
+ /** The result code when view activity should close after edit returns */
+ public static final int RESULT_CLOSE_VIEW_ACTIVITY = 777;
+
+ public static final int SAVE_MODE_DEFAULT = 0;
+ public static final int SAVE_MODE_SPLIT = 1;
+ public static final int SAVE_MODE_JOIN = 2;
+
+ private long mRawContactIdRequestingPhoto = -1;
+
+ private static final int DIALOG_CONFIRM_DELETE = 1;
+ private static final int DIALOG_CONFIRM_READONLY_DELETE = 2;
+ private static final int DIALOG_CONFIRM_MULTIPLE_DELETE = 3;
+ private static final int DIALOG_CONFIRM_READONLY_HIDE = 4;
+
+ String mQuerySelection;
+
+ private long mContactIdForJoin;
+ EntitySet mState;
+
+ /** The linear layout holding the ContactEditorViews */
+ LinearLayout mContent;
+
+ private ArrayList<Dialog> mManagedDialogs = Lists.newArrayList();
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final Intent intent = getIntent();
+ final String action = intent.getAction();
+
+ setContentView(R.layout.act_edit);
+
+ // Build editor and listen for photo requests
+ mContent = (LinearLayout) findViewById(R.id.editors);
+
+ findViewById(R.id.btn_done).setOnClickListener(this);
+ findViewById(R.id.btn_discard).setOnClickListener(this);
+
+ // Handle initial actions only when existing state missing
+ final boolean hasIncomingState = icicle != null && icicle.containsKey(KEY_EDIT_STATE);
+
+ if (Intent.ACTION_EDIT.equals(action) && !hasIncomingState) {
+ // Read initial state from database
+ new QueryEntitiesTask(this).execute(intent);
+ } else if (Intent.ACTION_INSERT.equals(action) && !hasIncomingState) {
+ // Trigger dialog to pick account type
+ doAddAction();
+ }
+ }
+
+ private static class QueryEntitiesTask extends
+ WeakAsyncTask<Intent, Void, Void, EditContactActivity> {
+ public QueryEntitiesTask(EditContactActivity target) {
+ super(target);
+ }
+
+ @Override
+ protected Void doInBackground(EditContactActivity target, Intent... params) {
+ // Load edit details in background
+ final Context context = target;
+ final Sources sources = Sources.getInstance(context);
+ final Intent intent = params[0];
+
+ final ContentResolver resolver = context.getContentResolver();
+
+ // Handle both legacy and new authorities
+ final Uri data = intent.getData();
+ final String authority = data.getAuthority();
+ final String mimeType = intent.resolveType(resolver);
+
+ String selection = "0";
+ if (ContactsContract.AUTHORITY.equals(authority)) {
+ if (Contacts.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ // Handle selected aggregate
+ final long contactId = ContentUris.parseId(data);
+ selection = RawContacts.CONTACT_ID + "=" + contactId;
+ } else if (RawContacts.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ final long rawContactId = ContentUris.parseId(data);
+ final long contactId = ContactsUtils.queryForContactId(resolver, rawContactId);
+ selection = RawContacts.CONTACT_ID + "=" + contactId;
+ }
+ } else if (android.provider.Contacts.AUTHORITY.equals(authority)) {
+ final long rawContactId = ContentUris.parseId(data);
+ selection = Data.RAW_CONTACT_ID + "=" + rawContactId;
+ }
+
+ target.mQuerySelection = selection;
+ target.mState = EntitySet.fromQuery(resolver, selection, null, null);
+
+ // Handle any incoming values that should be inserted
+ final Bundle extras = intent.getExtras();
+ final boolean hasExtras = extras != null && extras.size() > 0;
+ final boolean hasState = target.mState.size() > 0;
+ if (hasExtras && hasState) {
+ // Find source defining the first RawContact found
+ final EntityDelta state = target.mState.get(0);
+ final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ final ContactsSource source = sources.getInflatedSource(accountType,
+ ContactsSource.LEVEL_CONSTRAINTS);
+ EntityModifier.parseExtras(context, source, state, extras);
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(EditContactActivity target, Void result) {
+ // Bind UI to new background state
+ target.bindEditors();
+ }
+ }
+
+
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ if (hasValidState()) {
+ // Store entities with modifications
+ outState.putParcelable(KEY_EDIT_STATE, mState);
+ }
+
+ outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ // Read modifications from instance
+ mState = savedInstanceState.<EntitySet> getParcelable(KEY_EDIT_STATE);
+ mRawContactIdRequestingPhoto = savedInstanceState.getLong(
+ KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
+ bindEditors();
+
+ super.onRestoreInstanceState(savedInstanceState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ for (Dialog dialog : mManagedDialogs) {
+ if (dialog.isShowing()) {
+ dialog.dismiss();
+ }
+ }
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case DIALOG_CONFIRM_DELETE:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.deleteConfirmation)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, new DeleteClickListener())
+ .setCancelable(false)
+ .create();
+ case DIALOG_CONFIRM_READONLY_DELETE:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.readOnlyContactDeleteConfirmation)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, new DeleteClickListener())
+ .setCancelable(false)
+ .create();
+ case DIALOG_CONFIRM_MULTIPLE_DELETE:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.multipleContactDeleteConfirmation)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, new DeleteClickListener())
+ .setCancelable(false)
+ .create();
+ case DIALOG_CONFIRM_READONLY_HIDE:
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.deleteConfirmation_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.readOnlyContactWarning)
+ .setPositiveButton(android.R.string.ok, new DeleteClickListener())
+ .setCancelable(false)
+ .create();
+ }
+ return null;
+ }
+
+ /**
+ * Start managing this {@link Dialog} along with the {@link Activity}.
+ */
+ private void startManagingDialog(Dialog dialog) {
+ synchronized (mManagedDialogs) {
+ mManagedDialogs.add(dialog);
+ }
+ }
+
+ /**
+ * Show this {@link Dialog} and manage with the {@link Activity}.
+ */
+ void showAndManageDialog(Dialog dialog) {
+ startManagingDialog(dialog);
+ dialog.show();
+ }
+
+ /**
+ * Check if our internal {@link #mState} is valid, usually checked before
+ * performing user actions.
+ */
+ protected boolean hasValidState() {
+ return mState != null && mState.size() > 0;
+ }
+
+ /**
+ * Rebuild the editors to match our underlying {@link #mState} object, usually
+ * called once we've parsed {@link Entity} data or have inserted a new
+ * {@link RawContacts}.
+ */
+ protected void bindEditors() {
+ if (!hasValidState()) return;
+
+ final LayoutInflater inflater = (LayoutInflater) getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ final Sources sources = Sources.getInstance(this);
+
+ // Sort the editors
+ Collections.sort(mState, this);
+
+ // Remove any existing editors and rebuild any visible
+ mContent.removeAllViews();
+ int size = mState.size();
+ for (int i = 0; i < size; i++) {
+ // TODO ensure proper ordering of entities in the list
+ EntityDelta entity = mState.get(i);
+ final ValuesDelta values = entity.getValues();
+ if (!values.isVisible()) continue;
+
+ final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
+ final ContactsSource source = sources.getInflatedSource(accountType,
+ ContactsSource.LEVEL_CONSTRAINTS);
+ final long rawContactId = values.getAsLong(RawContacts._ID);
+
+ BaseContactEditorView editor;
+ if (!source.readOnly) {
+ editor = (BaseContactEditorView) inflater.inflate(R.layout.item_contact_editor,
+ mContent, false);
+ } else {
+ editor = (BaseContactEditorView) inflater.inflate(
+ R.layout.item_read_only_contact_editor, mContent, false);
+ }
+ PhotoEditorView photoEditor = editor.getPhotoEditor();
+ photoEditor.setEditorListener(new PhotoListener(rawContactId, source.readOnly,
+ photoEditor));
+
+ mContent.addView(editor);
+ editor.setState(entity, source);
+ }
+
+ // Show editor now that we've loaded state
+ mContent.setVisibility(View.VISIBLE);
+ }
+
+ /**
+ * Class that listens to requests coming from photo editors
+ */
+ private class PhotoListener implements EditorListener, DialogInterface.OnClickListener {
+ private long mRawContactId;
+ private boolean mReadOnly;
+ private PhotoEditorView mEditor;
+
+ public PhotoListener(long rawContactId, boolean readOnly, PhotoEditorView editor) {
+ mRawContactId = rawContactId;
+ mReadOnly = readOnly;
+ mEditor = editor;
+ }
+
+ public void onDeleted(Editor editor) {
+ // Do nothing
+ }
+
+ public void onRequest(int request) {
+ if (!hasValidState()) return;
+
+ if (request == EditorListener.REQUEST_PICK_PHOTO) {
+ if (mEditor.hasSetPhoto()) {
+ // There is an existing photo, offer to remove, replace, or promoto to primary
+ createPhotoDialog().show();
+ } else if (!mReadOnly) {
+ // No photo set and not read-only, try to set the photo
+ doPickPhotoAction(mRawContactId);
+ }
+ }
+ }
+
+ /**
+ * Prepare dialog for picking a new {@link EditType} or entering a
+ * custom label. This dialog is limited to the valid types as determined
+ * by {@link EntityModifier}.
+ */
+ public Dialog createPhotoDialog() {
+ Context context = EditContactActivity.this;
+
+ // Wrap our context to inflate list items using correct theme
+ final Context dialogContext = new ContextThemeWrapper(context,
+ android.R.style.Theme_Light);
+
+ String[] choices;
+ if (mReadOnly) {
+ choices = new String[1];
+ choices[0] = getString(R.string.use_photo_as_primary);
+ } else {
+ choices = new String[3];
+ choices[0] = getString(R.string.use_photo_as_primary);
+ choices[1] = getString(R.string.removePicture);
+ choices[2] = getString(R.string.changePicture);
+ }
+ final ListAdapter adapter = new ArrayAdapter<String>(dialogContext,
+ android.R.layout.simple_list_item_1, choices);
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(dialogContext);
+ builder.setTitle(R.string.attachToContact);
+ builder.setSingleChoiceItems(adapter, -1, this);
+ return builder.create();
+ }
+
+ /**
+ * Called when something in the dialog is clicked
+ */
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+
+ switch (which) {
+ case 0:
+ // Set the photo as super primary
+ mEditor.setSuperPrimary(true);
+
+ // And set all other photos as not super primary
+ int count = mContent.getChildCount();
+ for (int i = 0; i < count; i++) {
+ View childView = mContent.getChildAt(i);
+ if (childView instanceof BaseContactEditorView) {
+ BaseContactEditorView editor = (BaseContactEditorView) childView;
+ PhotoEditorView photoEditor = editor.getPhotoEditor();
+ if (!photoEditor.equals(mEditor)) {
+ photoEditor.setSuperPrimary(false);
+ }
+ }
+ }
+ break;
+
+ case 1:
+ // Remove the photo
+ mEditor.setPhotoBitmap(null);
+ break;
+
+ case 2:
+ // Pick a new photo for the contact
+ doPickPhotoAction(mRawContactId);
+ break;
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.btn_done:
+ doSaveAction(SAVE_MODE_DEFAULT);
+ break;
+ case R.id.btn_discard:
+ doRevertAction();
+ break;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onBackPressed() {
+ doSaveAction(SAVE_MODE_DEFAULT);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ // Ignore failed requests
+ if (resultCode != RESULT_OK) return;
+
+ switch (requestCode) {
+ case PHOTO_PICKED_WITH_DATA: {
+ BaseContactEditorView requestingEditor = null;
+ for (int i = 0; i < mContent.getChildCount(); i++) {
+ View childView = mContent.getChildAt(i);
+ if (childView instanceof BaseContactEditorView) {
+ BaseContactEditorView editor = (BaseContactEditorView) childView;
+ if (editor.getRawContactId() == mRawContactIdRequestingPhoto) {
+ requestingEditor = editor;
+ break;
+ }
+ }
+ }
+
+ if (requestingEditor != null) {
+ final Bitmap photo = data.getParcelableExtra("data");
+ requestingEditor.setPhotoBitmap(photo);
+ mRawContactIdRequestingPhoto = -1;
+ } else {
+ // The contact that requested the photo is no longer present.
+ // TODO: Show error message
+ }
+
+ break;
+ }
+
+ case REQUEST_JOIN_CONTACT: {
+ if (resultCode == RESULT_OK && data != null) {
+ final long contactId = ContentUris.parseId(data.getData());
+ joinAggregate(contactId);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.edit, menu);
+
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ menu.findItem(R.id.menu_split).setVisible(mState != null && mState.size() > 1);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_done:
+ return doSaveAction(SAVE_MODE_DEFAULT);
+ case R.id.menu_discard:
+ return doRevertAction();
+ case R.id.menu_add:
+ return doAddAction();
+ case R.id.menu_delete:
+ return doDeleteAction();
+ case R.id.menu_split:
+ return doSplitContactAction();
+ case R.id.menu_join:
+ return doJoinContactAction();
+ }
+ return false;
+ }
+
+ /**
+ * Background task for persisting edited contact data, using the changes
+ * defined by a set of {@link EntityDelta}. This task starts
+ * {@link EmptyService} to make sure the background thread can finish
+ * persisting in cases where the system wants to reclaim our process.
+ */
+ public static class PersistTask extends
+ WeakAsyncTask<EntitySet, Void, Integer, EditContactActivity> {
+ private static final int PERSIST_TRIES = 3;
+
+ private static final int RESULT_UNCHANGED = 0;
+ private static final int RESULT_SUCCESS = 1;
+ private static final int RESULT_FAILURE = 2;
+
+ private WeakReference<ProgressDialog> progress;
+
+ private int mSaveMode;
+ private Uri mContactLookupUri = null;
+
+ public PersistTask(EditContactActivity target, int saveMode) {
+ super(target);
+ mSaveMode = saveMode;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onPreExecute(EditContactActivity target) {
+ this.progress = new WeakReference<ProgressDialog>(ProgressDialog.show(target, null,
+ target.getText(R.string.savingContact)));
+
+ // Before starting this task, start an empty service to protect our
+ // process from being reclaimed by the system.
+ final Context context = target;
+ context.startService(new Intent(context, EmptyService.class));
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected Integer doInBackground(EditContactActivity target, EntitySet... params) {
+ final Context context = target;
+ final ContentResolver resolver = context.getContentResolver();
+
+ EntitySet state = params[0];
+
+ // Trim any empty fields, and RawContacts, before persisting
+ final Sources sources = Sources.getInstance(context);
+ EntityModifier.trimEmpty(state, sources);
+
+ // Attempt to persist changes
+ int tries = 0;
+ Integer result = RESULT_FAILURE;
+ while (tries++ < PERSIST_TRIES) {
+ try {
+ // Build operations and try applying
+ final ArrayList<ContentProviderOperation> diff = state.buildDiff();
+ ContentProviderResult[] results = null;
+ if (!diff.isEmpty()) {
+ results = resolver.applyBatch(ContactsContract.AUTHORITY, diff);
+ }
+
+ final long rawContactId = getRawContactId(state, diff, results);
+ if (rawContactId != -1) {
+ final Uri rawContactUri = ContentUris.withAppendedId(
+ RawContacts.CONTENT_URI, rawContactId);
+
+ // convert the raw contact URI to a contact URI
+ mContactLookupUri = RawContacts.getContactLookupUri(resolver,
+ rawContactUri);
+ }
+ result = (diff.size() > 0) ? RESULT_SUCCESS : RESULT_UNCHANGED;
+ break;
+
+ } catch (RemoteException e) {
+ // Something went wrong, bail without success
+ Log.e(TAG, "Problem persisting user edits", e);
+ break;
+
+ } catch (OperationApplicationException e) {
+ // Version consistency failed, re-parent change and try again
+ Log.w(TAG, "Version consistency failed, re-parenting: " + e.toString());
+ final EntitySet newState = EntitySet.fromQuery(resolver,
+ target.mQuerySelection, null, null);
+ state = EntitySet.mergeAfter(newState, state);
+ }
+ }
+
+ return result;
+ }
+
+ private long getRawContactId(EntitySet state,
+ final ArrayList<ContentProviderOperation> diff,
+ final ContentProviderResult[] results) {
+ long rawContactId = state.findRawContactId();
+ if (rawContactId != -1) {
+ return rawContactId;
+ }
+
+ // we gotta do some searching for the id
+ final int diffSize = diff.size();
+ for (int i = 0; i < diffSize; i++) {
+ ContentProviderOperation operation = diff.get(i);
+ if (operation.getType() == ContentProviderOperation.TYPE_INSERT
+ && operation.getUri().getEncodedPath().contains(
+ RawContacts.CONTENT_URI.getEncodedPath())) {
+ return ContentUris.parseId(results[i].uri);
+ }
+ }
+ return -1;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onPostExecute(EditContactActivity target, Integer result) {
+ final Context context = target;
+
+ if (result == RESULT_SUCCESS && mSaveMode != SAVE_MODE_JOIN) {
+ Toast.makeText(context, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
+ } else if (result == RESULT_FAILURE) {
+ Toast.makeText(context, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
+ }
+
+ progress.get().dismiss();
+
+ // Stop the service that was protecting us
+ context.stopService(new Intent(context, EmptyService.class));
+
+ target.onSaveCompleted(result != RESULT_FAILURE, mSaveMode, mContactLookupUri);
+ }
+ }
+
+ /**
+ * Saves or creates the contact based on the mode, and if successful
+ * finishes the activity.
+ */
+ boolean doSaveAction(int saveMode) {
+ if (!hasValidState()) return false;
+
+ final PersistTask task = new PersistTask(this, saveMode);
+ task.execute(mState);
+
+ return true;
+ }
+
+ private class DeleteClickListener implements DialogInterface.OnClickListener {
+
+ public void onClick(DialogInterface dialog, int which) {
+ Sources sources = Sources.getInstance(EditContactActivity.this);
+ // Mark all raw contacts for deletion
+ for (EntityDelta delta : mState) {
+ delta.markDeleted();
+ }
+ // Save the deletes
+ doSaveAction(SAVE_MODE_DEFAULT);
+ finish();
+ }
+ }
+
+ private void onSaveCompleted(boolean success, int saveMode, Uri contactLookupUri) {
+ switch (saveMode) {
+ case SAVE_MODE_DEFAULT:
+ if (success && contactLookupUri != null) {
+ final Intent resultIntent = new Intent();
+
+ final Uri requestData = getIntent().getData();
+ final String requestAuthority = requestData == null ? null : requestData
+ .getAuthority();
+
+ if (android.provider.Contacts.AUTHORITY.equals(requestAuthority)) {
+ // Build legacy Uri when requested by caller
+ final long contactId = ContentUris.parseId(Contacts.lookupContact(
+ getContentResolver(), contactLookupUri));
+ final Uri legacyUri = ContentUris.withAppendedId(
+ android.provider.Contacts.People.CONTENT_URI, contactId);
+ resultIntent.setData(legacyUri);
+ } else {
+ // Otherwise pass back a lookup-style Uri
+ resultIntent.setData(contactLookupUri);
+ }
+
+ setResult(RESULT_OK, resultIntent);
+ } else {
+ setResult(RESULT_CANCELED, null);
+ }
+ finish();
+ break;
+
+ case SAVE_MODE_SPLIT:
+ if (success) {
+ Intent intent = new Intent();
+ intent.setData(contactLookupUri);
+ setResult(RESULT_CLOSE_VIEW_ACTIVITY, intent);
+ }
+ finish();
+ break;
+
+ case SAVE_MODE_JOIN:
+ if (success) {
+ showJoinAggregateActivity(contactLookupUri);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Shows a list of aggregates that can be joined into the currently viewed aggregate.
+ *
+ * @param contactLookupUri the fresh URI for the currently edited contact (after saving it)
+ */
+ public void showJoinAggregateActivity(Uri contactLookupUri) {
+ if (contactLookupUri == null) {
+ return;
+ }
+
+ mContactIdForJoin = ContentUris.parseId(contactLookupUri);
+ Intent intent = new Intent(ContactsListActivity.JOIN_AGGREGATE);
+ intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_ID, mContactIdForJoin);
+ startActivityForResult(intent, REQUEST_JOIN_CONTACT);
+ }
+
+ /**
+ * Performs aggregation with the contact selected by the user from suggestions or A-Z list.
+ */
+ private void joinAggregate(final long contactId) {
+ ContentResolver resolver = getContentResolver();
+
+ // Load raw contact IDs for all raw contacts involved - currently edited and selected
+ // in the join UIs
+ Cursor c = resolver.query(RawContacts.CONTENT_URI,
+ new String[] {RawContacts._ID},
+ RawContacts.CONTACT_ID + "=" + contactId
+ + " OR " + RawContacts.CONTACT_ID + "=" + mContactIdForJoin, null, null);
+
+ long rawContactIds[];
+ try {
+ rawContactIds = new long[c.getCount()];
+ for (int i = 0; i < rawContactIds.length; i++) {
+ c.moveToNext();
+ rawContactIds[i] = c.getLong(0);
+ }
+ } finally {
+ c.close();
+ }
+
+ // For each pair of raw contacts, insert an aggregation exception
+ ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
+ for (int i = 0; i < rawContactIds.length; i++) {
+ for (int j = 0; j < rawContactIds.length; j++) {
+ if (i != j) {
+ buildJoinContactDiff(operations, rawContactIds[i], rawContactIds[j]);
+ }
+ }
+ }
+
+ // Apply all aggregation exceptions as one batch
+ try {
+ getContentResolver().applyBatch(ContactsContract.AUTHORITY, operations);
+
+ // We can use any of the constituent raw contacts to refresh the UI - why not the first
+ Intent intent = new Intent();
+ intent.setData(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactIds[0]));
+
+ // Reload the new state from database
+ new QueryEntitiesTask(this).execute(intent);
+
+ Toast.makeText(this, R.string.contactsJoinedMessage, Toast.LENGTH_LONG).show();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to apply aggregation exception batch", e);
+ Toast.makeText(this, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
+ } catch (OperationApplicationException e) {
+ Log.e(TAG, "Failed to apply aggregation exception batch", e);
+ Toast.makeText(this, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ /**
+ * Construct a {@link AggregationExceptions#TYPE_KEEP_TOGETHER} ContentProviderOperation.
+ */
+ private void buildJoinContactDiff(ArrayList<ContentProviderOperation> operations,
+ long rawContactId1, long rawContactId2) {
+ Builder builder =
+ ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI);
+ builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
+ operations.add(builder.build());
+ }
+
+ /**
+ * Revert any changes the user has made, and finish the activity.
+ */
+ private boolean doRevertAction() {
+ finish();
+ return true;
+ }
+
+ /**
+ * Create a new {@link RawContacts} which will exist as another
+ * {@link EntityDelta} under the currently edited {@link Contacts}.
+ */
+ private boolean doAddAction() {
+ // Adding is okay when missing state
+ new AddContactTask(this).execute();
+ return true;
+ }
+
+ /**
+ * Delete the entire contact currently being edited, which usually asks for
+ * user confirmation before continuing.
+ */
+ private boolean doDeleteAction() {
+ if (!hasValidState()) return false;
+ int readOnlySourcesCnt = 0;
+ int writableSourcesCnt = 0;
+ Sources sources = Sources.getInstance(EditContactActivity.this);
+ for (EntityDelta delta : mState) {
+ final String accountType = delta.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ final ContactsSource contactsSource = sources.getInflatedSource(accountType,
+ ContactsSource.LEVEL_CONSTRAINTS);
+ if (contactsSource != null && contactsSource.readOnly) {
+ readOnlySourcesCnt += 1;
+ } else {
+ writableSourcesCnt += 1;
+ }
+ }
+
+ if (readOnlySourcesCnt > 0 && writableSourcesCnt > 0) {
+ showDialog(DIALOG_CONFIRM_READONLY_DELETE);
+ } else if (readOnlySourcesCnt > 0 && writableSourcesCnt == 0) {
+ showDialog(DIALOG_CONFIRM_READONLY_HIDE);
+ } else if (readOnlySourcesCnt == 0 && writableSourcesCnt > 1) {
+ showDialog(DIALOG_CONFIRM_MULTIPLE_DELETE);
+ } else {
+ showDialog(DIALOG_CONFIRM_DELETE);
+ }
+ return true;
+ }
+
+ /**
+ * Pick a specific photo to be added under the currently selected tab.
+ */
+ boolean doPickPhotoAction(long rawContactId) {
+ if (!hasValidState()) return false;
+
+ try {
+ // Launch picker to choose photo for selected contact
+ final Intent intent = ContactsUtils.getPhotoPickIntent();
+ startActivityForResult(intent, PHOTO_PICKED_WITH_DATA);
+ mRawContactIdRequestingPhoto = rawContactId;
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(this, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
+ }
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ public void onDeleted(Editor editor) {
+ // Ignore any editor deletes
+ }
+
+ private boolean doSplitContactAction() {
+ if (!hasValidState()) return false;
+
+ showAndManageDialog(createSplitDialog());
+ return true;
+ }
+
+ private Dialog createSplitDialog() {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.splitConfirmation_title);
+ builder.setIcon(android.R.drawable.ic_dialog_alert);
+ builder.setMessage(R.string.splitConfirmation);
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Split the contacts
+ mState.splitRawContacts();
+ doSaveAction(SAVE_MODE_SPLIT);
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, null);
+ builder.setCancelable(false);
+ return builder.create();
+ }
+
+ private boolean doJoinContactAction() {
+ return doSaveAction(SAVE_MODE_JOIN);
+ }
+
+
+
+
+
+
+
+
+ /**
+ * Build dialog that handles adding a new {@link RawContacts} after the user
+ * picks a specific {@link ContactsSource}.
+ */
+ private static class AddContactTask extends
+ WeakAsyncTask<Void, Void, AlertDialog.Builder, EditContactActivity> {
+ public AddContactTask(EditContactActivity target) {
+ super(target);
+ }
+
+ @Override
+ protected AlertDialog.Builder doInBackground(final EditContactActivity target,
+ Void... params) {
+ final Sources sources = Sources.getInstance(target);
+
+ // Wrap our context to inflate list items using correct theme
+ final Context dialogContext = new ContextThemeWrapper(target, android.R.style.Theme_Light);
+ final LayoutInflater dialogInflater = (LayoutInflater)dialogContext
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ final ArrayList<Account> writable = sources.getAccounts(true);
+
+ // No Accounts available. Create a phone-local contact.
+ if (writable.isEmpty()) {
+ selectAccount(null);
+ return null; // Don't show a dialog.
+ }
+
+ // In the common case of a single account being writable, auto-select
+ // it without showing a dialog.
+ if (writable.size() == 1) {
+ selectAccount(writable.get(0));
+ return null; // Don't show a dialog.
+ }
+
+ final ArrayAdapter<Account> accountAdapter = new ArrayAdapter<Account>(target,
+ android.R.layout.simple_list_item_2, writable) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = dialogInflater.inflate(android.R.layout.simple_list_item_2,
+ parent, false);
+ }
+
+ // TODO: show icon along with title
+ final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
+ final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
+
+ final Account account = this.getItem(position);
+ final ContactsSource source = sources.getInflatedSource(account.type,
+ ContactsSource.LEVEL_SUMMARY);
+
+ text1.setText(account.name);
+ text2.setText(source.getDisplayLabel(target));
+
+ return convertView;
+ }
+ };
+
+ final DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+
+ // Create new contact based on selected source
+ final Account account = accountAdapter.getItem(which);
+ selectAccount(account);
+
+ // Update the UI.
+ EditContactActivity target = mTarget.get();
+ if (target != null) {
+ target.bindEditors();
+ }
+ }
+ };
+
+ final DialogInterface.OnCancelListener cancelListener = new DialogInterface.OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ // If nothing remains, close activity
+ if (!target.hasValidState()) {
+ target.finish();
+ }
+ }
+ };
+
+ // TODO: when canceled and was single add, finish()
+ final AlertDialog.Builder builder = new AlertDialog.Builder(target);
+ builder.setTitle(R.string.dialog_new_contact_account);
+ builder.setSingleChoiceItems(accountAdapter, 0, clickListener);
+ builder.setOnCancelListener(cancelListener);
+ return builder;
+ }
+
+ /**
+ * Sets up EditContactActivity's mState for the account selected.
+ * Runs from a background thread.
+ *
+ * @param account may be null to signal a device-local contact should
+ * be created.
+ */
+ private void selectAccount(Account account) {
+ EditContactActivity target = mTarget.get();
+ if (target == null) {
+ return;
+ }
+ final Sources sources = Sources.getInstance(target);
+ final ContentValues values = new ContentValues();
+ if (account != null) {
+ values.put(RawContacts.ACCOUNT_NAME, account.name);
+ values.put(RawContacts.ACCOUNT_TYPE, account.type);
+ } else {
+ values.putNull(RawContacts.ACCOUNT_NAME);
+ values.putNull(RawContacts.ACCOUNT_TYPE);
+ }
+
+ // Parse any values from incoming intent
+ final EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values));
+ final ContactsSource source = sources.getInflatedSource(
+ account != null ? account.type : null,
+ ContactsSource.LEVEL_CONSTRAINTS);
+ final Bundle extras = target.getIntent().getExtras();
+ EntityModifier.parseExtras(target, source, insert, extras);
+
+ // Ensure we have some default fields
+ EntityModifier.ensureKindExists(insert, source, Phone.CONTENT_ITEM_TYPE);
+ EntityModifier.ensureKindExists(insert, source, Email.CONTENT_ITEM_TYPE);
+
+ // Create "My Contacts" membership for Google contacts
+ // TODO: move this off into "templates" for each given source
+ if (GoogleSource.ACCOUNT_TYPE.equals(source.accountType)) {
+ GoogleSource.attemptMyContactsMembership(insert, target);
+ }
+
+ // TODO: no synchronization here on target.mState. This
+ // runs in the background thread, but it's accessed from
+ // multiple thread, including the UI thread.
+ if (target.mState == null) {
+ // Create state if none exists yet
+ target.mState = EntitySet.fromSingle(insert);
+ } else {
+ // Add contact onto end of existing state
+ target.mState.add(insert);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(EditContactActivity target, AlertDialog.Builder result) {
+ if (result != null) {
+ // Note: null is returned when no dialog is to be
+ // shown (no multiple accounts to select between)
+ target.showAndManageDialog(result.create());
+ } else {
+ // Account was auto-selected on the background thread,
+ // but we need to update the UI still in the
+ // now-current UI thread.
+ target.bindEditors();
+ }
+ }
+ }
+
+
+
+ private Dialog createDeleteDialog() {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.deleteConfirmation_title);
+ builder.setIcon(android.R.drawable.ic_dialog_alert);
+ builder.setMessage(R.string.deleteConfirmation);
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Mark all raw contacts for deletion
+ for (EntityDelta delta : mState) {
+ delta.markDeleted();
+ }
+
+ // Save the deletes
+ doSaveAction(SAVE_MODE_DEFAULT);
+ finish();
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, null);
+ builder.setCancelable(false);
+ return builder.create();
+ }
+
+ /**
+ * Create dialog for selecting primary display name.
+ */
+ private Dialog createNameDialog() {
+ // Build set of all available display names
+ final ArrayList<ValuesDelta> allNames = Lists.newArrayList();
+ for (EntityDelta entity : mState) {
+ final ArrayList<ValuesDelta> displayNames = entity
+ .getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
+ allNames.addAll(displayNames);
+ }
+
+ // Wrap our context to inflate list items using correct theme
+ final Context dialogContext = new ContextThemeWrapper(this, android.R.style.Theme_Light);
+ final LayoutInflater dialogInflater = this.getLayoutInflater()
+ .cloneInContext(dialogContext);
+
+ final ListAdapter nameAdapter = new ArrayAdapter<ValuesDelta>(this,
+ android.R.layout.simple_list_item_1, allNames) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = dialogInflater.inflate(android.R.layout.simple_list_item_1,
+ parent, false);
+ }
+
+ final ValuesDelta structuredName = this.getItem(position);
+ final String displayName = structuredName.getAsString(StructuredName.DISPLAY_NAME);
+
+ ((TextView)convertView).setText(displayName);
+
+ return convertView;
+ }
+ };
+
+ final DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+
+ // User picked display name, so make super-primary
+ final ValuesDelta structuredName = allNames.get(which);
+ structuredName.put(Data.IS_PRIMARY, 1);
+ structuredName.put(Data.IS_SUPER_PRIMARY, 1);
+ }
+ };
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.dialog_primary_name);
+ builder.setSingleChoiceItems(nameAdapter, 0, clickListener);
+ return builder.create();
+ }
+
+ /**
+ * Compare EntityDeltas for sorting the stack of editors.
+ */
+ public int compare(EntityDelta one, EntityDelta two) {
+ // Check direct equality
+ if (one.equals(two)) {
+ return 0;
+ }
+
+ final Sources sources = Sources.getInstance(this);
+ String accountType = one.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ final ContactsSource oneSource = sources.getInflatedSource(accountType,
+ ContactsSource.LEVEL_SUMMARY);
+ accountType = two.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ final ContactsSource twoSource = sources.getInflatedSource(accountType,
+ ContactsSource.LEVEL_SUMMARY);
+
+ // Check read-only
+ if (oneSource.readOnly && !twoSource.readOnly) {
+ return 1;
+ } else if (twoSource.readOnly && !oneSource.readOnly) {
+ return -1;
+ }
+
+ // Check account type
+ boolean skipAccountTypeCheck = false;
+ boolean oneIsGoogle = oneSource instanceof GoogleSource;
+ boolean twoIsGoogle = twoSource instanceof GoogleSource;
+ if (oneIsGoogle && !twoIsGoogle) {
+ return -1;
+ } else if (twoIsGoogle && !oneIsGoogle) {
+ return 1;
+ } else {
+ skipAccountTypeCheck = true;
+ }
+
+ int value;
+ if (!skipAccountTypeCheck) {
+ value = oneSource.accountType.compareTo(twoSource.accountType);
+ if (value != 0) {
+ return value;
+ }
+ }
+
+ // Check account name
+ ValuesDelta oneValues = one.getValues();
+ String oneAccount = oneValues.getAsString(RawContacts.ACCOUNT_NAME);
+ if (oneAccount == null) oneAccount = "";
+ ValuesDelta twoValues = two.getValues();
+ String twoAccount = twoValues.getAsString(RawContacts.ACCOUNT_NAME);
+ if (twoAccount == null) twoAccount = "";
+ value = oneAccount.compareTo(twoAccount);
+ if (value != 0) {
+ return value;
+ }
+
+ // Both are in the same account, fall back to contact ID
+ long oneId = oneValues.getAsLong(RawContacts._ID);
+ long twoId = twoValues.getAsLong(RawContacts._ID);
+ return (int)(oneId - twoId);
+ }
+}
diff --git a/src/com/android/contacts/ui/QuickContactActivity.java b/src/com/android/contacts/ui/QuickContactActivity.java
new file mode 100644
index 0000000..d17e3be
--- /dev/null
+++ b/src/com/android/contacts/ui/QuickContactActivity.java
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract.QuickContact;
+import android.util.Log;
+
+/**
+ * Stub translucent activity that just shows {@link QuickContactWindow} floating
+ * above the caller. This temporary hack should eventually be replaced with
+ * direct framework support.
+ */
+public final class QuickContactActivity extends Activity implements
+ QuickContactWindow.OnDismissListener {
+ private static final String TAG = "QuickContactActivity";
+
+ static final boolean LOGV = true;
+ static final boolean FORCE_CREATE = false;
+
+ private QuickContactWindow mQuickContact;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ if (LOGV) Log.d(TAG, "onCreate");
+
+ this.onNewIntent(getIntent());
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ if (LOGV) Log.d(TAG, "onNewIntent");
+
+ if (QuickContactWindow.TRACE_LAUNCH) {
+ android.os.Debug.startMethodTracing(QuickContactWindow.TRACE_TAG);
+ }
+
+ if (mQuickContact == null || FORCE_CREATE) {
+ if (LOGV) Log.d(TAG, "Preparing window");
+ mQuickContact = new QuickContactWindow(this, this);
+ }
+
+ // Use our local window token for now
+ final Uri lookupUri = intent.getData();
+ final Bundle extras = intent.getExtras();
+
+ // Read requested parameters for displaying
+ final Rect target = (Rect)extras.getParcelable(QuickContact.EXTRA_TARGET_RECT);
+ final int mode = extras.getInt(QuickContact.EXTRA_MODE, QuickContact.MODE_MEDIUM);
+ final String[] excludeMimes = extras.getStringArray(QuickContact.EXTRA_EXCLUDE_MIMES);
+
+ mQuickContact.show(lookupUri, target, mode, excludeMimes);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onBackPressed() {
+ if (LOGV) Log.w(TAG, "Unexpected back captured by stub activity");
+ finish();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (LOGV) Log.d(TAG, "onPause");
+
+ // Dismiss any dialog when pausing
+ mQuickContact.dismiss();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (LOGV) Log.d(TAG, "onDestroy");
+ }
+
+ /** {@inheritDoc} */
+ public void onDismiss(QuickContactWindow dialog) {
+ if (LOGV) Log.d(TAG, "onDismiss");
+
+ if (isTaskRoot() && !FORCE_CREATE) {
+ // Instead of stopping, simply push this to the back of the stack.
+ // This is only done when running at the top of the stack;
+ // otherwise, we have been launched by someone else so need to
+ // allow the user to go back to the caller.
+ moveTaskToBack(false);
+ } else {
+ finish();
+ }
+ }
+}
diff --git a/src/com/android/contacts/ui/QuickContactWindow.java b/src/com/android/contacts/ui/QuickContactWindow.java
new file mode 100644
index 0000000..e787987
--- /dev/null
+++ b/src/com/android/contacts/ui/QuickContactWindow.java
@@ -0,0 +1,1582 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui;
+
+import com.android.contacts.ContactsUtils;
+import com.android.contacts.R;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.Sources;
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.ui.widget.CheckableImageView;
+import com.android.contacts.util.Constants;
+import com.android.contacts.util.DataStatus;
+import com.android.contacts.util.NotifyingAsyncQueryHandler;
+import com.android.internal.policy.PolicyManager;
+import com.google.android.collect.Sets;
+
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.EntityIterator;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.QuickContact;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.StatusUpdates;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.AbsListView;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.HorizontalScrollView;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.lang.ref.SoftReference;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Window that shows QuickContact dialog for a specific {@link Contacts#_ID}.
+ */
+public class QuickContactWindow implements Window.Callback,
+ NotifyingAsyncQueryHandler.AsyncQueryListener, View.OnClickListener,
+ AbsListView.OnItemClickListener, CompoundButton.OnCheckedChangeListener, KeyEvent.Callback,
+ OnGlobalLayoutListener {
+ private static final String TAG = "QuickContactWindow";
+
+ /**
+ * Interface used to allow the person showing a {@link QuickContactWindow} to
+ * know when the window has been dismissed.
+ */
+ public interface OnDismissListener {
+ public void onDismiss(QuickContactWindow dialog);
+ }
+
+ private final Context mContext;
+ private final LayoutInflater mInflater;
+ private final WindowManager mWindowManager;
+ private Window mWindow;
+ private View mDecor;
+ private final Rect mRect = new Rect();
+
+ private boolean mDismissed = false;
+ private boolean mQuerying = false;
+ private boolean mShowing = false;
+
+ private NotifyingAsyncQueryHandler mHandler;
+ private OnDismissListener mDismissListener;
+ private ResolveCache mResolveCache;
+
+ private Uri mLookupUri;
+ private Rect mAnchor;
+
+ private int mShadowHoriz;
+ private int mShadowVert;
+ private int mShadowTouch;
+
+ private int mScreenWidth;
+ private int mScreenHeight;
+ private int mRequestedY;
+
+ private boolean mHasValidSocial = false;
+ private boolean mHasData = false;
+ private boolean mMakePrimary = false;
+
+ private ImageView mArrowUp;
+ private ImageView mArrowDown;
+
+ private int mMode;
+ private View mHeader;
+ private HorizontalScrollView mTrackScroll;
+ private ViewGroup mTrack;
+ private Animation mTrackAnim;
+
+ private View mFooter;
+ private View mFooterDisambig;
+ private ListView mResolveList;
+ private CheckableImageView mLastAction;
+ private CheckBox mSetPrimaryCheckBox;
+
+ private int mWindowRecycled = 0;
+ private int mActionRecycled = 0;
+
+ /**
+ * Set of {@link Action} that are associated with the aggregate currently
+ * displayed by this dialog, represented as a map from {@link String}
+ * MIME-type to {@link ActionList}.
+ */
+ private ActionMap mActions = new ActionMap();
+
+ /**
+ * Pool of unused {@link CheckableImageView} that have previously been
+ * inflated, and are ready to be recycled through {@link #obtainView()}.
+ */
+ private LinkedList<View> mActionPool = new LinkedList<View>();
+
+ private String[] mExcludeMimes;
+
+ /**
+ * Specific MIME-types that should be bumped to the front of the dialog.
+ * Other MIME-types not appearing in this list follow in alphabetic order.
+ */
+ private static final String[] ORDERED_MIMETYPES = new String[] {
+ Phone.CONTENT_ITEM_TYPE,
+ Contacts.CONTENT_ITEM_TYPE,
+ Constants.MIME_SMS_ADDRESS,
+ Email.CONTENT_ITEM_TYPE,
+ };
+
+ /**
+ * Specific list {@link ApplicationInfo#packageName} of apps that are
+ * prefered <strong>only</strong> for the purposes of default icons when
+ * multiple {@link ResolveInfo} are found to match. This only happens when
+ * the user has not selected a default app yet, and they will still be
+ * presented with the system disambiguation dialog.
+ */
+ private static final HashSet<String> sPreferResolve = Sets.newHashSet(new String[] {
+ "com.android.email",
+ "com.android.calendar",
+ "com.android.contacts",
+ "com.android.mms",
+ "com.android.phone",
+ });
+
+ private static final int TOKEN_DATA = 1;
+
+ static final boolean LOGD = false;
+
+ static final boolean TRACE_LAUNCH = false;
+ static final String TRACE_TAG = "quickcontact";
+
+ /**
+ * Prepare a dialog to show in the given {@link Context}.
+ */
+ public QuickContactWindow(Context context) {
+ mContext = new ContextThemeWrapper(context, R.style.QuickContact);
+ mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+
+ mWindow = PolicyManager.makeNewWindow(mContext);
+ mWindow.setCallback(this);
+ mWindow.setWindowManager(mWindowManager, null, null);
+
+ mWindow.setContentView(R.layout.quickcontact);
+
+ mArrowUp = (ImageView)mWindow.findViewById(R.id.arrow_up);
+ mArrowDown = (ImageView)mWindow.findViewById(R.id.arrow_down);
+
+ mResolveCache = new ResolveCache(mContext);
+
+ final Resources res = mContext.getResources();
+ mShadowHoriz = res.getDimensionPixelSize(R.dimen.quickcontact_shadow_horiz);
+ mShadowVert = res.getDimensionPixelSize(R.dimen.quickcontact_shadow_vert);
+ mShadowTouch = res.getDimensionPixelSize(R.dimen.quickcontact_shadow_touch);
+
+ mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
+ mScreenHeight = mWindowManager.getDefaultDisplay().getHeight();
+
+ mTrack = (ViewGroup)mWindow.findViewById(R.id.quickcontact);
+ mTrackScroll = (HorizontalScrollView)mWindow.findViewById(R.id.scroll);
+
+ mFooter = mWindow.findViewById(R.id.footer);
+ mFooterDisambig = mWindow.findViewById(R.id.footer_disambig);
+ mResolveList = (ListView)mWindow.findViewById(android.R.id.list);
+ mSetPrimaryCheckBox = (CheckBox)mWindow.findViewById(android.R.id.checkbox);
+
+ mSetPrimaryCheckBox.setOnCheckedChangeListener(this);
+
+ // Prepare track entrance animation
+ mTrackAnim = AnimationUtils.loadAnimation(mContext, R.anim.quickcontact);
+ mTrackAnim.setInterpolator(new Interpolator() {
+ public float getInterpolation(float t) {
+ // Pushes past the target area, then snaps back into place.
+ // Equation for graphing: 1.2-((x*1.6)-1.1)^2
+ final float inner = (t * 1.55f) - 1.1f;
+ return 1.2f - inner * inner;
+ }
+ });
+
+ mHandler = new NotifyingAsyncQueryHandler(mContext, this);
+ }
+
+ /**
+ * Prepare a dialog to show in the given {@link Context}, and notify the
+ * given {@link OnDismissListener} each time this dialog is dismissed.
+ */
+ public QuickContactWindow(Context context, OnDismissListener dismissListener) {
+ this(context);
+ mDismissListener = dismissListener;
+ }
+
+ private View getHeaderView(int mode) {
+ View header = null;
+ switch (mode) {
+ case QuickContact.MODE_SMALL:
+ header = mWindow.findViewById(R.id.header_small);
+ break;
+ case QuickContact.MODE_MEDIUM:
+ header = mWindow.findViewById(R.id.header_medium);
+ break;
+ case QuickContact.MODE_LARGE:
+ header = mWindow.findViewById(R.id.header_large);
+ break;
+ }
+
+ if (header instanceof ViewStub) {
+ // Inflate actual header if we picked a stub
+ final ViewStub stub = (ViewStub)header;
+ header = stub.inflate();
+ } else {
+ header.setVisibility(View.VISIBLE);
+ }
+
+ return header;
+ }
+
+ /**
+ * Start showing a dialog for the given {@link Contacts#_ID} pointing
+ * towards the given location.
+ */
+ public synchronized void show(Uri lookupUri, Rect anchor, int mode, String[] excludeMimes) {
+ if (mQuerying || mShowing) {
+ Log.w(TAG, "dismissing before showing");
+ dismissInternal();
+ }
+
+ if (TRACE_LAUNCH && !android.os.Debug.isMethodTracingActive()) {
+ android.os.Debug.startMethodTracing(TRACE_TAG);
+ }
+
+ // Prepare header view for requested mode
+ mLookupUri = lookupUri;
+ mAnchor = new Rect(anchor);
+ mMode = mode;
+ mExcludeMimes = excludeMimes;
+
+ mHeader = getHeaderView(mode);
+
+ setHeaderText(R.id.name, R.string.quickcontact_missing_name);
+
+ setHeaderText(R.id.status, null);
+ setHeaderText(R.id.timestamp, null);
+
+ setHeaderImage(R.id.presence, null);
+
+ resetTrack();
+
+ mHasValidSocial = false;
+ mDismissed = false;
+ mQuerying = true;
+
+ // Start background query for data, but only select photo rows when they
+ // directly match the super-primary PHOTO_ID.
+ final Uri dataUri = getDataUri(lookupUri);
+ mHandler.cancelOperation(TOKEN_DATA);
+
+ // Only request photo data when required by mode
+ if (mMode == QuickContact.MODE_LARGE) {
+ // Select photos, but only super-primary
+ mHandler.startQuery(TOKEN_DATA, lookupUri, dataUri, DataQuery.PROJECTION, Data.MIMETYPE
+ + "!=? OR (" + Data.MIMETYPE + "=? AND " + Data._ID + "=" + Contacts.PHOTO_ID
+ + ")", new String[] { Photo.CONTENT_ITEM_TYPE, Photo.CONTENT_ITEM_TYPE }, null);
+ } else {
+ // Exclude all photos from cursor
+ mHandler.startQuery(TOKEN_DATA, lookupUri, dataUri, DataQuery.PROJECTION, Data.MIMETYPE
+ + "!=?", new String[] { Photo.CONTENT_ITEM_TYPE }, null);
+ }
+ }
+
+ /**
+ * Build a {@link Uri} into the {@link Data} table for the requested
+ * {@link Contacts#CONTENT_LOOKUP_URI} style {@link Uri}.
+ */
+ private Uri getDataUri(Uri lookupUri) {
+ // TODO: Formalize method of extracting LOOKUP_KEY
+ final List<String> path = lookupUri.getPathSegments();
+ final boolean validLookup = path.size() >= 3 && "lookup".equals(path.get(1));
+ if (!validLookup) {
+ // We only accept valid lookup-style Uris
+ throw new IllegalArgumentException("Expecting lookup-style Uri");
+ } else if (path.size() == 3) {
+ // No direct _ID provided, so force a lookup
+ lookupUri = Contacts.lookupContact(mContext.getContentResolver(), lookupUri);
+ }
+
+ final long contactId = ContentUris.parseId(lookupUri);
+ return Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
+ Contacts.Data.CONTENT_DIRECTORY);
+ }
+
+ /**
+ * Show the correct call-out arrow based on a {@link R.id} reference.
+ */
+ private void showArrow(int whichArrow, int requestedX) {
+ final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp : mArrowDown;
+ final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown : mArrowUp;
+
+ final int arrowWidth = mArrowUp.getMeasuredWidth();
+
+ showArrow.setVisibility(View.VISIBLE);
+ ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams)showArrow.getLayoutParams();
+ param.leftMargin = requestedX - arrowWidth / 2;
+
+ hideArrow.setVisibility(View.INVISIBLE);
+ }
+
+ /**
+ * Actual internal method to show this dialog. Called only by
+ * {@link #considerShowing()} when all data requirements have been met.
+ */
+ private void showInternal() {
+ mDecor = mWindow.getDecorView();
+ mDecor.getViewTreeObserver().addOnGlobalLayoutListener(this);
+ WindowManager.LayoutParams l = mWindow.getAttributes();
+
+ l.width = mScreenWidth + mShadowHoriz + mShadowHoriz;
+ l.height = WindowManager.LayoutParams.WRAP_CONTENT;
+
+ // Force layout measuring pass so we have baseline numbers
+ mDecor.measure(l.width, l.height);
+ final int blockHeight = mDecor.getMeasuredHeight();
+
+ l.gravity = Gravity.TOP | Gravity.LEFT;
+ l.x = -mShadowHoriz;
+
+ if (mAnchor.top > blockHeight) {
+ // Show downwards callout when enough room, aligning bottom block
+ // edge with top of anchor area, and adjusting to inset arrow.
+ showArrow(R.id.arrow_down, mAnchor.centerX());
+ l.y = mAnchor.top - blockHeight + mShadowVert;
+ l.windowAnimations = R.style.QuickContactAboveAnimation;
+
+ } else {
+ // Otherwise show upwards callout, aligning block top with bottom of
+ // anchor area, and adjusting to inset arrow.
+ showArrow(R.id.arrow_up, mAnchor.centerX());
+ l.y = mAnchor.bottom - mShadowVert;
+ l.windowAnimations = R.style.QuickContactBelowAnimation;
+
+ }
+
+ l.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+
+ mRequestedY = l.y;
+ mWindowManager.addView(mDecor, l);
+ mShowing = true;
+ mQuerying = false;
+ mDismissed = false;
+
+ mTrack.startAnimation(mTrackAnim);
+
+ if (TRACE_LAUNCH) {
+ android.os.Debug.stopMethodTracing();
+ Log.d(TAG, "Window recycled " + mWindowRecycled + " times, chiclets "
+ + mActionRecycled + " times");
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void onGlobalLayout() {
+ layoutInScreen();
+ }
+
+ /**
+ * Adjust vertical {@link WindowManager.LayoutParams} to fit window as best
+ * as possible, shifting up to display content as needed.
+ */
+ private void layoutInScreen() {
+ if (!mShowing) return;
+
+ final WindowManager.LayoutParams l = mWindow.getAttributes();
+ final int originalY = l.y;
+
+ final int blockHeight = mDecor.getHeight();
+
+ l.y = mRequestedY;
+ if (mRequestedY + blockHeight > mScreenHeight) {
+ // Shift up from bottom when overflowing
+ l.y = mScreenHeight - blockHeight;
+ }
+
+ if (originalY != l.y) {
+ // Only update when value is changed
+ mWindow.setAttributes(l);
+ }
+ }
+
+ /**
+ * Dismiss this dialog if showing.
+ */
+ public synchronized void dismiss() {
+ // Notify any listeners that we've been dismissed
+ if (mDismissListener != null) {
+ mDismissListener.onDismiss(this);
+ }
+
+ dismissInternal();
+ }
+
+ private void dismissInternal() {
+ // Remove any attached window decor for recycling
+ boolean hadDecor = mDecor != null;
+ if (hadDecor) {
+ mWindowManager.removeView(mDecor);
+ mWindowRecycled++;
+ mDecor.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+ mDecor = null;
+ mWindow.closeAllPanels();
+ }
+ mShowing = false;
+ mDismissed = true;
+
+ // Cancel any pending queries
+ mHandler.cancelOperation(TOKEN_DATA);
+ mQuerying = false;
+
+ // Completely hide header and reset track
+ mHeader.setVisibility(View.GONE);
+ resetTrack();
+ }
+
+ /**
+ * Reset track to initial state, recycling any chiclets.
+ */
+ private void resetTrack() {
+ // Release reference to last chiclet
+ mLastAction = null;
+
+ // Clear track actions and scroll to hard left
+ mResolveCache.clear();
+ mActions.clear();
+
+ // Recycle any chiclets in use
+ while (mTrack.getChildCount() > 2) {
+ this.releaseView(mTrack.getChildAt(1));
+ mTrack.removeViewAt(1);
+ }
+
+ mTrackScroll.fullScroll(View.FOCUS_LEFT);
+ mWasDownArrow = false;
+
+ // Clear any primary requests
+ mMakePrimary = false;
+ mSetPrimaryCheckBox.setChecked(false);
+
+ setResolveVisible(false, null);
+ }
+
+ /**
+ * Consider showing this window, which will only call through to
+ * {@link #showInternal()} when all data items are present.
+ */
+ private void considerShowing() {
+ if (mHasData && !mShowing && !mDismissed) {
+ if (mMode == QuickContact.MODE_MEDIUM && !mHasValidSocial) {
+ // Missing valid social, swap medium for small header
+ mHeader.setVisibility(View.GONE);
+ mHeader = getHeaderView(QuickContact.MODE_SMALL);
+ }
+
+ // All queries have returned, pull curtain
+ showInternal();
+ }
+ }
+
+ /** {@inheritDoc} */
+ public synchronized void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ // Bail early when query is stale
+ if (cookie != mLookupUri) return;
+
+ if (cursor == null) {
+ // Problem while running query, so bail without showing
+ Log.w(TAG, "Missing cursor for token=" + token);
+ this.dismiss();
+ return;
+ }
+
+ handleData(cursor);
+ mHasData = true;
+
+ if (!cursor.isClosed()) {
+ cursor.close();
+ }
+
+ considerShowing();
+ }
+
+ /** Assign this string to the view, if found in {@link #mHeader}. */
+ private void setHeaderText(int id, int resId) {
+ setHeaderText(id, mContext.getResources().getText(resId));
+ }
+
+ /** Assign this string to the view, if found in {@link #mHeader}. */
+ private void setHeaderText(int id, CharSequence value) {
+ final View view = mHeader.findViewById(id);
+ if (view instanceof TextView) {
+ ((TextView)view).setText(value);
+ view.setVisibility(TextUtils.isEmpty(value) ? View.GONE : View.VISIBLE);
+ }
+ }
+
+ /** Assign this image to the view, if found in {@link #mHeader}. */
+ private void setHeaderImage(int id, int resId) {
+ setHeaderImage(id, mContext.getResources().getDrawable(resId));
+ }
+
+ /** Assign this image to the view, if found in {@link #mHeader}. */
+ private void setHeaderImage(int id, Drawable drawable) {
+ final View view = mHeader.findViewById(id);
+ if (view instanceof ImageView) {
+ ((ImageView)view).setImageDrawable(drawable);
+ view.setVisibility(drawable == null ? View.GONE : View.VISIBLE);
+ }
+ }
+
+ /**
+ * Find the presence icon for showing in summary header.
+ */
+ private Drawable getPresenceIcon(int status) {
+ int resId = -1;
+ switch (status) {
+ case StatusUpdates.AVAILABLE:
+ resId = android.R.drawable.presence_online;
+ break;
+ case StatusUpdates.IDLE:
+ case StatusUpdates.AWAY:
+ resId = android.R.drawable.presence_away;
+ break;
+ case StatusUpdates.DO_NOT_DISTURB:
+ resId = android.R.drawable.presence_busy;
+ break;
+ }
+ if (resId != -1) {
+ return mContext.getResources().getDrawable(resId);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find the QuickContact-specific presence icon for showing in chiclets.
+ */
+ private Drawable getTrackPresenceIcon(int status) {
+ int resId = -1;
+ switch (status) {
+ case StatusUpdates.AVAILABLE:
+ resId = R.drawable.quickcontact_slider_presence_active;
+ break;
+ case StatusUpdates.IDLE:
+ case StatusUpdates.AWAY:
+ resId = R.drawable.quickcontact_slider_presence_away;
+ break;
+ case StatusUpdates.DO_NOT_DISTURB:
+ resId = R.drawable.quickcontact_slider_presence_busy;
+ break;
+ case StatusUpdates.INVISIBLE:
+ resId = R.drawable.quickcontact_slider_presence_inactive;
+ break;
+ case StatusUpdates.OFFLINE:
+ default:
+ resId = R.drawable.quickcontact_slider_presence_inactive;
+ }
+ return mContext.getResources().getDrawable(resId);
+ }
+
+ /** Read {@link String} from the given {@link Cursor}. */
+ private static String getAsString(Cursor cursor, String columnName) {
+ final int index = cursor.getColumnIndex(columnName);
+ return cursor.getString(index);
+ }
+
+ /** Read {@link Integer} from the given {@link Cursor}. */
+ private static int getAsInt(Cursor cursor, String columnName) {
+ final int index = cursor.getColumnIndex(columnName);
+ return cursor.getInt(index);
+ }
+
+ /**
+ * Abstract definition of an action that could be performed, along with
+ * string description and icon.
+ */
+ private interface Action {
+ public CharSequence getHeader();
+ public CharSequence getBody();
+
+ public String getMimeType();
+ public Drawable getFallbackIcon();
+
+ /**
+ * Build an {@link Intent} that will perform this action.
+ */
+ public Intent getIntent();
+
+ /**
+ * Checks if the contact data for this action is primary.
+ */
+ public Boolean isPrimary();
+
+ /**
+ * Returns a lookup (@link Uri) for the contact data item.
+ */
+ public Uri getDataUri();
+ }
+
+ /**
+ * Description of a specific {@link Data#_ID} item, with style information
+ * defined by a {@link DataKind}.
+ */
+ private static class DataAction implements Action {
+ private final Context mContext;
+ private final DataKind mKind;
+ private final String mMimeType;
+
+ private CharSequence mHeader;
+ private CharSequence mBody;
+ private Intent mIntent;
+
+ private boolean mAlternate;
+ private Uri mDataUri;
+ private boolean mIsPrimary;
+
+ /**
+ * Create an action from common {@link Data} elements.
+ */
+ public DataAction(Context context, String mimeType, DataKind kind,
+ long dataId, Cursor cursor) {
+ mContext = context;
+ mKind = kind;
+ mMimeType = mimeType;
+
+ // Inflate strings from cursor
+ mAlternate = Constants.MIME_SMS_ADDRESS.equals(mimeType);
+ if (mAlternate && mKind.actionAltHeader != null) {
+ mHeader = mKind.actionAltHeader.inflateUsing(context, cursor);
+ } else if (mKind.actionHeader != null) {
+ mHeader = mKind.actionHeader.inflateUsing(context, cursor);
+ }
+
+ if (getAsInt(cursor, Data.IS_SUPER_PRIMARY) != 0) {
+ mIsPrimary = true;
+ }
+
+ if (mKind.actionBody != null) {
+ mBody = mKind.actionBody.inflateUsing(context, cursor);
+ }
+
+ mDataUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId);
+
+ // Handle well-known MIME-types with special care
+ if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ final String number = getAsString(cursor, Phone.NUMBER);
+ if (!TextUtils.isEmpty(number)) {
+ final Uri callUri = Uri.fromParts(Constants.SCHEME_TEL, number, null);
+ mIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, callUri);
+ }
+
+ } else if (Constants.MIME_SMS_ADDRESS.equals(mimeType)) {
+ final String number = getAsString(cursor, Phone.NUMBER);
+ if (!TextUtils.isEmpty(number)) {
+ final Uri smsUri = Uri.fromParts(Constants.SCHEME_SMSTO, number, null);
+ mIntent = new Intent(Intent.ACTION_SENDTO, smsUri);
+ }
+
+ } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ final String address = getAsString(cursor, Email.DATA);
+ if (!TextUtils.isEmpty(address)) {
+ final Uri mailUri = Uri.fromParts(Constants.SCHEME_MAILTO, address, null);
+ mIntent = new Intent(Intent.ACTION_SENDTO, mailUri);
+ }
+
+ } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(
+ getAsString(cursor, Data.MIMETYPE));
+ if (isEmail || isProtocolValid(cursor)) {
+ final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK :
+ getAsInt(cursor, Im.PROTOCOL);
+
+ if (isEmail) {
+ // Use Google Talk string when using Email, and clear data
+ // Uri so we don't try saving Email as primary.
+ mHeader = context.getText(R.string.chat_gtalk);
+ mDataUri = null;
+ }
+
+ String host = getAsString(cursor, Im.CUSTOM_PROTOCOL);
+ String data = getAsString(cursor, isEmail ? Email.DATA : Im.DATA);
+ if (protocol != Im.PROTOCOL_CUSTOM) {
+ // Try bringing in a well-known host for specific protocols
+ host = ContactsUtils.lookupProviderNameFromId(protocol);
+ }
+
+ if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(data)) {
+ final String authority = host.toLowerCase();
+ final Uri imUri = new Uri.Builder().scheme(Constants.SCHEME_IMTO).authority(
+ authority).appendPath(data).build();
+ mIntent = new Intent(Intent.ACTION_SENDTO, imUri);
+ }
+ }
+ }
+
+ if (mIntent == null) {
+ // Otherwise fall back to default VIEW action
+ mIntent = new Intent(Intent.ACTION_VIEW, mDataUri);
+ }
+
+ // Always launch as new task, since we're like a launcher
+ mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ }
+
+ private boolean isProtocolValid(Cursor cursor) {
+ final int columnIndex = cursor.getColumnIndex(Im.PROTOCOL);
+ if (cursor.isNull(columnIndex)) {
+ return false;
+ }
+ try {
+ Integer.valueOf(cursor.getString(columnIndex));
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ public CharSequence getHeader() {
+ return mHeader;
+ }
+
+ /** {@inheritDoc} */
+ public CharSequence getBody() {
+ return mBody;
+ }
+
+ /** {@inheritDoc} */
+ public String getMimeType() {
+ return mMimeType;
+ }
+
+ /** {@inheritDoc} */
+ public Uri getDataUri() {
+ return mDataUri;
+ }
+
+ /** {@inheritDoc} */
+ public Boolean isPrimary() {
+ return mIsPrimary;
+ }
+
+ /** {@inheritDoc} */
+ public Drawable getFallbackIcon() {
+ // Bail early if no valid resources
+ final String resPackageName = mKind.resPackageName;
+ if (resPackageName == null) return null;
+
+ final PackageManager pm = mContext.getPackageManager();
+ if (mAlternate && mKind.iconAltRes != -1) {
+ return pm.getDrawable(resPackageName, mKind.iconAltRes, null);
+ } else if (mKind.iconRes != -1) {
+ return pm.getDrawable(resPackageName, mKind.iconRes, null);
+ } else {
+ return null;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public Intent getIntent() {
+ return mIntent;
+ }
+ }
+
+ /**
+ * Specific action that launches the profile card.
+ */
+ private static class ProfileAction implements Action {
+ private final Context mContext;
+ private final Uri mLookupUri;
+
+ public ProfileAction(Context context, Uri lookupUri) {
+ mContext = context;
+ mLookupUri = lookupUri;
+ }
+
+ /** {@inheritDoc} */
+ public CharSequence getHeader() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public CharSequence getBody() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public String getMimeType() {
+ return Contacts.CONTENT_ITEM_TYPE;
+ }
+
+ /** {@inheritDoc} */
+ public Drawable getFallbackIcon() {
+ return mContext.getResources().getDrawable(R.drawable.ic_contacts_details);
+ }
+
+ /** {@inheritDoc} */
+ public Intent getIntent() {
+ final Intent intent = new Intent(Intent.ACTION_VIEW, mLookupUri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ return intent;
+ }
+
+ /** {@inheritDoc} */
+ public Boolean isPrimary() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public Uri getDataUri() {
+ return null;
+ }
+
+ }
+
+ /**
+ * Internally hold a cache of scaled icons based on {@link PackageManager}
+ * queries, keyed internally on MIME-type.
+ */
+ private static class ResolveCache {
+ private Context mContext;
+ private PackageManager mPackageManager;
+
+ /**
+ * Cached entry holding the best {@link ResolveInfo} for a specific
+ * MIME-type, along with a {@link SoftReference} to its icon.
+ */
+ private static class Entry {
+ public ResolveInfo bestResolve;
+ public SoftReference<Drawable> icon;
+ }
+
+ private HashMap<String, Entry> mCache = new HashMap<String, Entry>();
+
+ public ResolveCache(Context context) {
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ }
+
+ /**
+ * Get the {@link Entry} best associated with the given {@link Action},
+ * or create and populate a new one if it doesn't exist.
+ */
+ protected Entry getEntry(Action action) {
+ final String mimeType = action.getMimeType();
+ Entry entry = mCache.get(mimeType);
+ if (entry != null) return entry;
+ entry = new Entry();
+
+ final Intent intent = action.getIntent();
+ if (intent != null) {
+ final List<ResolveInfo> matches = mPackageManager.queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+
+ // Pick first match, otherwise best found
+ ResolveInfo bestResolve = null;
+ final int size = matches.size();
+ if (size == 1) {
+ bestResolve = matches.get(0);
+ } else if (size > 1) {
+ bestResolve = getBestResolve(intent, matches);
+ }
+
+ if (bestResolve != null) {
+ final Drawable icon = bestResolve.loadIcon(mPackageManager);
+
+ entry.bestResolve = bestResolve;
+ entry.icon = new SoftReference<Drawable>(icon);
+ }
+ }
+
+ mCache.put(mimeType, entry);
+ return entry;
+ }
+
+ /**
+ * Best {@link ResolveInfo} when multiple found. Ties are broken by
+ * selecting first from the {QuickContactWindow#sPreferResolve} list of
+ * preferred packages, second by apps that live on the system partition,
+ * otherwise the app from the top of the list. This is
+ * <strong>only</strong> used for selecting a default icon for
+ * displaying in the track, and does not shortcut the system
+ * {@link Intent} disambiguation dialog.
+ */
+ protected ResolveInfo getBestResolve(Intent intent, List<ResolveInfo> matches) {
+ // Try finding preferred activity, otherwise detect disambig
+ final ResolveInfo foundResolve = mPackageManager.resolveActivity(intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ final boolean foundDisambig = (foundResolve.match &
+ IntentFilter.MATCH_CATEGORY_MASK) == 0;
+
+ if (!foundDisambig) {
+ // Found concrete match, so return directly
+ return foundResolve;
+ }
+
+ // Accept any package from prefer list, otherwise first system app
+ ResolveInfo firstSystem = null;
+ for (ResolveInfo info : matches) {
+ final boolean isSystem = (info.activityInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_SYSTEM) != 0;
+ final boolean isPrefer = QuickContactWindow.sPreferResolve
+ .contains(info.activityInfo.applicationInfo.packageName);
+
+
+
+ if (isPrefer) return info;
+ if (isSystem && firstSystem != null) firstSystem = info;
+ }
+
+ // Return first system found, otherwise first from list
+ return firstSystem != null ? firstSystem : matches.get(0);
+ }
+
+ /**
+ * Check {@link PackageManager} to see if any apps offer to handle the
+ * given {@link Action}.
+ */
+ public boolean hasResolve(Action action) {
+ return getEntry(action).bestResolve != null;
+ }
+
+ /**
+ * Find the best description for the given {@link Action}, usually used
+ * for accessibility purposes.
+ */
+ public CharSequence getDescription(Action action) {
+ final CharSequence actionHeader = action.getHeader();
+ final ResolveInfo info = getEntry(action).bestResolve;
+ if (!TextUtils.isEmpty(actionHeader)) {
+ return actionHeader;
+ } else if (info != null) {
+ return info.loadLabel(mPackageManager);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Return the best icon for the given {@link Action}, which is usually
+ * based on the {@link ResolveInfo} found through a
+ * {@link PackageManager} query.
+ */
+ public Drawable getIcon(Action action) {
+ final SoftReference<Drawable> iconRef = getEntry(action).icon;
+ return (iconRef == null) ? null : iconRef.get();
+ }
+
+ public void clear() {
+ mCache.clear();
+ }
+ }
+
+ /**
+ * Provide a strongly-typed {@link LinkedList} that holds a list of
+ * {@link Action} objects.
+ */
+ private class ActionList extends LinkedList<Action> {
+ }
+
+ /**
+ * Provide a simple way of collecting one or more {@link Action} objects
+ * under a MIME-type key.
+ */
+ private class ActionMap extends HashMap<String, ActionList> {
+ private void collect(String mimeType, Action info) {
+ // Create list for this MIME-type when needed
+ ActionList collectList = get(mimeType);
+ if (collectList == null) {
+ collectList = new ActionList();
+ put(mimeType, collectList);
+ }
+ collectList.add(info);
+ }
+ }
+
+ /**
+ * Check if the given MIME-type appears in the list of excluded MIME-types
+ * that the most-recent caller requested.
+ */
+ private boolean isMimeExcluded(String mimeType) {
+ if (mExcludeMimes == null) return false;
+ for (String excludedMime : mExcludeMimes) {
+ if (TextUtils.equals(excludedMime, mimeType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Handle the result from the {@link #TOKEN_DATA} query.
+ */
+ private void handleData(Cursor cursor) {
+ if (cursor == null) return;
+
+ if (!isMimeExcluded(Contacts.CONTENT_ITEM_TYPE)) {
+ // Add the profile shortcut action
+ final Action action = new ProfileAction(mContext, mLookupUri);
+ mActions.collect(Contacts.CONTENT_ITEM_TYPE, action);
+ }
+
+ final DataStatus status = new DataStatus();
+ final Sources sources = Sources.getInstance(mContext);
+ final ImageView photoView = (ImageView)mHeader.findViewById(R.id.photo);
+
+ Bitmap photoBitmap = null;
+ while (cursor.moveToNext()) {
+ final long dataId = cursor.getLong(DataQuery._ID);
+ final String accountType = cursor.getString(DataQuery.ACCOUNT_TYPE);
+ final String resPackage = cursor.getString(DataQuery.RES_PACKAGE);
+ final String mimeType = cursor.getString(DataQuery.MIMETYPE);
+
+ // Handle any social status updates from this row
+ status.possibleUpdate(cursor);
+
+ // Skip this data item if MIME-type excluded
+ if (isMimeExcluded(mimeType)) continue;
+
+ // Handle photos included as data row
+ if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ final int colPhoto = cursor.getColumnIndex(Photo.PHOTO);
+ final byte[] photoBlob = cursor.getBlob(colPhoto);
+ if (photoBlob != null) {
+ photoBitmap = BitmapFactory.decodeByteArray(photoBlob, 0, photoBlob.length);
+ }
+ continue;
+ }
+
+ final DataKind kind = sources.getKindOrFallback(accountType, mimeType, mContext,
+ ContactsSource.LEVEL_MIMETYPES);
+
+ if (kind != null) {
+ // Build an action for this data entry, find a mapping to a UI
+ // element, build its summary from the cursor, and collect it
+ // along with all others of this MIME-type.
+ final Action action = new DataAction(mContext, mimeType, kind, dataId, cursor);
+ considerAdd(action, mimeType);
+ }
+
+ // If phone number, also insert as text message action
+ if (Phone.CONTENT_ITEM_TYPE.equals(mimeType) && kind != null) {
+ final Action action = new DataAction(mContext, Constants.MIME_SMS_ADDRESS,
+ kind, dataId, cursor);
+ considerAdd(action, Constants.MIME_SMS_ADDRESS);
+ }
+
+ // Handle Email rows with presence data as Im entry
+ final boolean hasPresence = !cursor.isNull(DataQuery.PRESENCE);
+ if (hasPresence && Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ final DataKind imKind = sources.getKindOrFallback(accountType,
+ Im.CONTENT_ITEM_TYPE, mContext, ContactsSource.LEVEL_MIMETYPES);
+ if (imKind != null) {
+ final Action action = new DataAction(mContext, Im.CONTENT_ITEM_TYPE, imKind,
+ dataId, cursor);
+ considerAdd(action, Im.CONTENT_ITEM_TYPE);
+ }
+ }
+ }
+
+ if (cursor.moveToLast()) {
+ // Read contact information from last data row
+ final String name = cursor.getString(DataQuery.DISPLAY_NAME);
+ final int presence = cursor.getInt(DataQuery.CONTACT_PRESENCE);
+ final Drawable statusIcon = getPresenceIcon(presence);
+
+ setHeaderText(R.id.name, name);
+ setHeaderImage(R.id.presence, statusIcon);
+ }
+
+ if (photoView != null) {
+ // Place photo when discovered in data, otherwise hide
+ photoView.setVisibility(photoBitmap != null ? View.VISIBLE : View.GONE);
+ photoView.setImageBitmap(photoBitmap);
+ }
+
+ mHasValidSocial = status.isValid();
+ if (mHasValidSocial && mMode != QuickContact.MODE_SMALL) {
+ // Update status when valid was found
+ setHeaderText(R.id.status, status.getStatus());
+ setHeaderText(R.id.timestamp, status.getTimestampLabel(mContext));
+ }
+
+ // Turn our list of actions into UI elements, starting with common types
+ final Set<String> containedTypes = mActions.keySet();
+ for (String mimeType : ORDERED_MIMETYPES) {
+ if (containedTypes.contains(mimeType)) {
+ final int index = mTrack.getChildCount() - 1;
+ mTrack.addView(inflateAction(mimeType), index);
+ containedTypes.remove(mimeType);
+ }
+ }
+
+ // Then continue with remaining MIME-types in alphabetical order
+ final String[] remainingTypes = containedTypes.toArray(new String[containedTypes.size()]);
+ Arrays.sort(remainingTypes);
+ for (String mimeType : remainingTypes) {
+ final int index = mTrack.getChildCount() - 1;
+ mTrack.addView(inflateAction(mimeType), index);
+ }
+ }
+
+ /**
+ * Consider adding the given {@link Action}, which will only happen if
+ * {@link PackageManager} finds an application to handle
+ * {@link Action#getIntent()}.
+ */
+ private void considerAdd(Action action, String mimeType) {
+ if (mResolveCache.hasResolve(action)) {
+ mActions.collect(mimeType, action);
+ }
+ }
+
+ /**
+ * Obtain a new {@link CheckableImageView} for a new chiclet, either by
+ * recycling one from {@link #mActionPool}, or by inflating a new one. When
+ * finished, use {@link #releaseView(View)} to return back into the pool for
+ * later recycling.
+ */
+ private synchronized View obtainView() {
+ View view = mActionPool.poll();
+ if (view == null || QuickContactActivity.FORCE_CREATE) {
+ view = mInflater.inflate(R.layout.quickcontact_item, mTrack, false);
+ }
+ return view;
+ }
+
+ /**
+ * Return the given {@link CheckableImageView} into our internal pool for
+ * possible recycling during another pass.
+ */
+ private synchronized void releaseView(View view) {
+ mActionPool.offer(view);
+ mActionRecycled++;
+ }
+
+ /**
+ * Inflate the in-track view for the action of the given MIME-type. Will use
+ * the icon provided by the {@link DataKind}.
+ */
+ private View inflateAction(String mimeType) {
+ final CheckableImageView view = (CheckableImageView)obtainView();
+ boolean isActionSet = false;
+
+ // Add direct intent if single child, otherwise flag for multiple
+ ActionList children = mActions.get(mimeType);
+ Action firstInfo = children.get(0);
+ if (children.size() == 1) {
+ view.setTag(firstInfo);
+ } else {
+ for (Action action : children) {
+ if (action.isPrimary()) {
+ view.setTag(action);
+ isActionSet = true;
+ break;
+ }
+ }
+ if (!isActionSet) {
+ view.setTag(children);
+ }
+ }
+
+ // Set icon and listen for clicks
+ final CharSequence descrip = mResolveCache.getDescription(firstInfo);
+ final Drawable icon = mResolveCache.getIcon(firstInfo);
+ view.setChecked(false);
+ view.setContentDescription(descrip);
+ view.setImageDrawable(icon);
+ view.setOnClickListener(this);
+ return view;
+ }
+
+ /** {@inheritDoc} */
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ // Pass list item clicks along so that Intents are handled uniformly
+ onClick(view);
+ }
+
+ /**
+ * Flag indicating if {@link #mArrowDown} was visible during the last call
+ * to {@link #setResolveVisible(boolean, CheckableImageView)}. Used to
+ * decide during a later call if the arrow should be restored.
+ */
+ private boolean mWasDownArrow = false;
+
+ /**
+ * Helper for showing and hiding {@link #mFooterDisambig}, which will
+ * correctly manage {@link #mArrowDown} as needed.
+ */
+ private void setResolveVisible(boolean visible, CheckableImageView actionView) {
+ // Show or hide the resolve list if needed
+ boolean visibleNow = mFooterDisambig.getVisibility() == View.VISIBLE;
+
+ if (mLastAction != null) mLastAction.setChecked(false);
+ if (actionView != null) actionView.setChecked(true);
+ mLastAction = actionView;
+
+ // Bail early if already in desired state
+ if (visible == visibleNow) return;
+
+ mFooter.setVisibility(visible ? View.GONE : View.VISIBLE);
+ mFooterDisambig.setVisibility(visible ? View.VISIBLE : View.GONE);
+
+ if (visible) {
+ // If showing list, then hide and save state of down arrow
+ mWasDownArrow = mWasDownArrow || (mArrowDown.getVisibility() == View.VISIBLE);
+ mArrowDown.setVisibility(View.INVISIBLE);
+ } else {
+ // If hiding list, restore any down arrow state
+ mArrowDown.setVisibility(mWasDownArrow ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void onClick(View view) {
+ final boolean isActionView = (view instanceof CheckableImageView);
+ final CheckableImageView actionView = isActionView ? (CheckableImageView)view : null;
+ final Object tag = view.getTag();
+ if (tag instanceof Action) {
+ // Incoming tag is concrete intent, so try launching
+ final Action action = (Action)tag;
+ final boolean makePrimary = mMakePrimary;
+
+ try {
+ mContext.startActivity(action.getIntent());
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(mContext, R.string.quickcontact_missing_app, Toast.LENGTH_SHORT)
+ .show();
+ }
+
+ // Hide the resolution list, if present
+ setResolveVisible(false, null);
+ this.dismiss();
+
+ if (makePrimary) {
+ ContentValues values = new ContentValues(1);
+ values.put(Data.IS_SUPER_PRIMARY, 1);
+ final Uri dataUri = action.getDataUri();
+ if (dataUri != null) {
+ mContext.getContentResolver().update(dataUri, values, null, null);
+ }
+ }
+ } else if (tag instanceof ActionList) {
+ // Incoming tag is a MIME-type, so show resolution list
+ final ActionList children = (ActionList)tag;
+
+ // Show resolution list and set adapter
+ setResolveVisible(true, actionView);
+
+ mResolveList.setOnItemClickListener(this);
+ mResolveList.setAdapter(new BaseAdapter() {
+ public int getCount() {
+ return children.size();
+ }
+
+ public Object getItem(int position) {
+ return children.get(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(
+ R.layout.quickcontact_resolve_item, parent, false);
+ }
+
+ // Set action title based on summary value
+ final Action action = (Action)getItem(position);
+ final Drawable icon = mResolveCache.getIcon(action);
+
+ TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
+ TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
+
+ text1.setText(action.getHeader());
+ text2.setText(action.getBody());
+
+ convertView.setTag(action);
+ return convertView;
+ }
+ });
+
+ // Make sure we resize to make room for ListView
+ mDecor.forceLayout();
+ mDecor.invalidate();
+
+ }
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mMakePrimary = isChecked;
+ }
+
+ private void onBackPressed() {
+ // Back key will first dismiss any expanded resolve list, otherwise
+ // it will close the entire dialog.
+ if (mFooterDisambig.getVisibility() == View.VISIBLE) {
+ setResolveVisible(false, null);
+ mDecor.forceLayout();
+ mDecor.invalidate();
+ } else {
+ dismiss();
+ }
+ }
+
+ /** {@inheritDoc} */
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (mWindow.superDispatchKeyEvent(event)) {
+ return true;
+ }
+ return event.dispatch(this, mDecor != null
+ ? mDecor.getKeyDispatcherState() : null, this);
+ }
+
+ /** {@inheritDoc} */
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ event.startTracking();
+ return true;
+ }
+
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
+ && !event.isCanceled()) {
+ onBackPressed();
+ return true;
+ }
+
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ // TODO: make this window accessible
+ return false;
+ }
+
+ /**
+ * Detect if the given {@link MotionEvent} is outside the boundaries of this
+ * window, which usually means we should dismiss.
+ */
+ protected void detectEventOutside(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ // Only try detecting outside events on down-press
+ mDecor.getHitRect(mRect);
+ mRect.top = mRect.top + mShadowTouch;
+ mRect.bottom = mRect.bottom - mShadowTouch;
+ final int x = (int)event.getX();
+ final int y = (int)event.getY();
+ if (!mRect.contains(x, y)) {
+ event.setAction(MotionEvent.ACTION_OUTSIDE);
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ detectEventOutside(event);
+ if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+ dismiss();
+ return true;
+ } else {
+ return mWindow.superDispatchTouchEvent(event);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public boolean dispatchTrackballEvent(MotionEvent event) {
+ return mWindow.superDispatchTrackballEvent(event);
+ }
+
+ /** {@inheritDoc} */
+ public void onContentChanged() {
+ }
+
+ /** {@inheritDoc} */
+ public boolean onCreatePanelMenu(int featureId, Menu menu) {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public View onCreatePanelView(int featureId) {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public boolean onMenuOpened(int featureId, Menu menu) {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public void onPanelClosed(int featureId, Menu menu) {
+ }
+
+ /** {@inheritDoc} */
+ public boolean onPreparePanel(int featureId, View view, Menu menu) {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public boolean onSearchRequested() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams attrs) {
+ if (mDecor != null) {
+ mWindowManager.updateViewLayout(mDecor, attrs);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void onWindowFocusChanged(boolean hasFocus) {
+ }
+
+ /** {@inheritDoc} */
+ public void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
+ // No actions
+ }
+
+ /** {@inheritDoc} */
+ public void onAttachedToWindow() {
+ // No actions
+ }
+
+ /** {@inheritDoc} */
+ public void onDetachedFromWindow() {
+ // No actions
+ }
+
+ private interface DataQuery {
+ final String[] PROJECTION = new String[] {
+ Data._ID,
+
+ RawContacts.ACCOUNT_TYPE,
+ Contacts.STARRED,
+ Contacts.DISPLAY_NAME,
+ Contacts.CONTACT_PRESENCE,
+
+ Data.STATUS,
+ Data.STATUS_RES_PACKAGE,
+ Data.STATUS_ICON,
+ Data.STATUS_LABEL,
+ Data.STATUS_TIMESTAMP,
+ Data.PRESENCE,
+
+ Data.RES_PACKAGE,
+ Data.MIMETYPE,
+ Data.IS_PRIMARY,
+ Data.IS_SUPER_PRIMARY,
+ Data.RAW_CONTACT_ID,
+
+ Data.DATA1, Data.DATA2, Data.DATA3, Data.DATA4, Data.DATA5,
+ Data.DATA6, Data.DATA7, Data.DATA8, Data.DATA9, Data.DATA10, Data.DATA11,
+ Data.DATA12, Data.DATA13, Data.DATA14, Data.DATA15,
+ };
+
+ final int _ID = 0;
+
+ final int ACCOUNT_TYPE = 1;
+ final int STARRED = 2;
+ final int DISPLAY_NAME = 3;
+ final int CONTACT_PRESENCE = 4;
+
+ final int STATUS = 5;
+ final int STATUS_RES_PACKAGE = 6;
+ final int STATUS_ICON = 7;
+ final int STATUS_LABEL = 8;
+ final int STATUS_TIMESTAMP = 9;
+ final int PRESENCE = 10;
+
+ final int RES_PACKAGE = 11;
+ final int MIMETYPE = 12;
+ final int IS_PRIMARY = 13;
+ final int IS_SUPER_PRIMARY = 14;
+ }
+}
diff --git a/src/com/android/contacts/ui/ShowOrCreateActivity.java b/src/com/android/contacts/ui/ShowOrCreateActivity.java
new file mode 100755
index 0000000..7728b36
--- /dev/null
+++ b/src/com/android/contacts/ui/ShowOrCreateActivity.java
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui;
+
+import com.android.contacts.ContactsListActivity;
+import com.android.contacts.R;
+import com.android.contacts.util.Constants;
+import com.android.contacts.util.NotifyingAsyncQueryHandler;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ComponentName;
+import android.content.ContentUris;
+import android.content.DialogInterface;
+import android.content.EntityIterator;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.util.Log;
+
+/**
+ * Handle several edge cases around showing or possibly creating contacts in
+ * connected with a specific E-mail address or phone number. Will search based
+ * on incoming {@link Intent#getData()} as described by
+ * {@link Intents#SHOW_OR_CREATE_CONTACT}.
+ * <ul>
+ * <li>If no matching contacts found, will prompt user with dialog to add to a
+ * contact, then will use {@link Intent#ACTION_INSERT_OR_EDIT} to let create new
+ * contact or edit new data into an existing one.
+ * <li>If one matching contact found, directly show {@link Intent#ACTION_VIEW}
+ * that specific contact.
+ * <li>If more than one matching found, show list of matching contacts using
+ * {@link Intent#ACTION_SEARCH}.
+ * </ul>
+ */
+public final class ShowOrCreateActivity extends Activity implements
+ NotifyingAsyncQueryHandler.AsyncQueryListener {
+ static final String TAG = "ShowOrCreateActivity";
+ static final boolean LOGD = false;
+
+ static final String[] PHONES_PROJECTION = new String[] {
+ PhoneLookup._ID,
+ };
+
+ static final String[] CONTACTS_PROJECTION = new String[] {
+ RawContacts.CONTACT_ID,
+ };
+
+ static final int CONTACT_ID_INDEX = 0;
+
+ static final int CREATE_CONTACT_DIALOG = 1;
+
+ static final int QUERY_TOKEN = 42;
+
+ private NotifyingAsyncQueryHandler mQueryHandler;
+
+ private Bundle mCreateExtras;
+ private String mCreateDescrip;
+ private boolean mCreateForce;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create handler if doesn't exist, otherwise cancel any running
+ if (mQueryHandler == null) {
+ mQueryHandler = new NotifyingAsyncQueryHandler(this, this);
+ } else {
+ mQueryHandler.cancelOperation(QUERY_TOKEN);
+ }
+
+ final Intent intent = getIntent();
+ final Uri data = intent.getData();
+
+ // Unpack scheme and target data from intent
+ String scheme = null;
+ String ssp = null;
+ if (data != null) {
+ scheme = data.getScheme();
+ ssp = data.getSchemeSpecificPart();
+ }
+
+ // Build set of extras for possible use when creating contact
+ mCreateExtras = new Bundle();
+ Bundle originalExtras = intent.getExtras();
+ if (originalExtras != null) {
+ mCreateExtras.putAll(originalExtras);
+ }
+
+ // Read possible extra with specific title
+ mCreateDescrip = intent.getStringExtra(Intents.EXTRA_CREATE_DESCRIPTION);
+ if (mCreateDescrip == null) {
+ mCreateDescrip = ssp;
+ }
+
+ // Allow caller to bypass dialog prompt
+ mCreateForce = intent.getBooleanExtra(Intents.EXTRA_FORCE_CREATE, false);
+
+ // Handle specific query request
+ if (Constants.SCHEME_MAILTO.equals(scheme)) {
+ mCreateExtras.putString(Intents.Insert.EMAIL, ssp);
+
+ Uri uri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, Uri.encode(ssp));
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri, CONTACTS_PROJECTION, null, null, null);
+
+ } else if (Constants.SCHEME_TEL.equals(scheme)) {
+ mCreateExtras.putString(Intents.Insert.PHONE, ssp);
+
+ Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, ssp);
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri, PHONES_PROJECTION, null, null, null);
+
+ } else {
+ Log.w(TAG, "Invalid intent:" + getIntent());
+ finish();
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (mQueryHandler != null) {
+ mQueryHandler.cancelOperation(QUERY_TOKEN);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ if (cursor == null) {
+ // Bail when problem running query in background
+ finish();
+ return;
+ }
+
+ // Count contacts found by query
+ int count = 0;
+ long contactId = -1;
+ try {
+ count = cursor.getCount();
+ if (count == 1 && cursor.moveToFirst()) {
+ // Try reading ID if only one contact returned
+ contactId = cursor.getLong(CONTACT_ID_INDEX);
+ }
+ } finally {
+ cursor.close();
+ }
+
+ if (count == 1 && contactId != -1) {
+ // If we only found one item, jump right to viewing it
+ final Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+ final Intent viewIntent = new Intent(Intent.ACTION_VIEW, contactUri);
+ startActivity(viewIntent);
+ finish();
+
+ } else if (count > 1) {
+ // If more than one, show pick list
+ Intent listIntent = new Intent(Intent.ACTION_SEARCH);
+ listIntent.setComponent(new ComponentName(this, ContactsListActivity.class));
+ listIntent.putExtras(mCreateExtras);
+ startActivity(listIntent);
+ finish();
+
+ } else {
+ // No matching contacts found
+ if (mCreateForce) {
+ // Forced to create new contact
+ Intent createIntent = new Intent(Intent.ACTION_INSERT, RawContacts.CONTENT_URI);
+ createIntent.putExtras(mCreateExtras);
+ createIntent.setType(RawContacts.CONTENT_TYPE);
+
+ startActivity(createIntent);
+ finish();
+
+ } else {
+ showDialog(CREATE_CONTACT_DIALOG);
+ }
+ }
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch(id) {
+ case CREATE_CONTACT_DIALOG:
+ // Prompt user to insert or edit contact
+ final Intent createIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
+ createIntent.putExtras(mCreateExtras);
+ createIntent.setType(RawContacts.CONTENT_ITEM_TYPE);
+
+ final CharSequence message = getResources().getString(
+ R.string.add_contact_dlg_message_fmt, mCreateDescrip);
+
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.add_contact_dlg_title)
+ .setMessage(message)
+ .setPositiveButton(android.R.string.ok,
+ new IntentClickListener(this, createIntent))
+ .setNegativeButton(android.R.string.cancel,
+ new IntentClickListener(this, null))
+ .create();
+ }
+ return super.onCreateDialog(id);
+ }
+
+ /** {@inheritDoc} */
+ public void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
+ // No actions
+ }
+
+ /**
+ * Listener for {@link DialogInterface} that launches a given {@link Intent}
+ * when clicked. When clicked, this also closes the parent using
+ * {@link Activity#finish()}.
+ */
+ private static class IntentClickListener implements DialogInterface.OnClickListener {
+ private Activity mParent;
+ private Intent mIntent;
+
+ /**
+ * @param parent {@link Activity} to use for launching target.
+ * @param intent Target {@link Intent} to launch when clicked.
+ */
+ public IntentClickListener(Activity parent, Intent intent) {
+ mParent = parent;
+ mIntent = intent;
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (mIntent != null) {
+ mParent.startActivity(mIntent);
+ }
+ mParent.finish();
+ }
+ }
+}
diff --git a/src/com/android/contacts/ui/widget/BaseContactEditorView.java b/src/com/android/contacts/ui/widget/BaseContactEditorView.java
new file mode 100644
index 0000000..189e2d5
--- /dev/null
+++ b/src/com/android/contacts/ui/widget/BaseContactEditorView.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui.widget;
+
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.Editor.EditorListener;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+
+import android.content.Context;
+import android.content.Entity;
+import android.graphics.Bitmap;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+
+/**
+ * Base view that provides common code for the editor interaction for a specific
+ * RawContact represented through an {@link EntityDelta}. Callers can
+ * reuse this view and quickly rebuild its contents through
+ * {@link #setState(EntityDelta, ContactsSource)}.
+ * <p>
+ * Internal updates are performed against {@link ValuesDelta} so that the
+ * source {@link Entity} can be swapped out. Any state-based changes, such as
+ * adding {@link Data} rows or changing {@link EditType}, are performed through
+ * {@link EntityModifier} to ensure that {@link ContactsSource} are enforced.
+ */
+public abstract class BaseContactEditorView extends LinearLayout {
+ protected LayoutInflater mInflater;
+
+ protected PhotoEditorView mPhoto;
+ protected boolean mHasPhotoEditor = false;
+
+ public BaseContactEditorView(Context context) {
+ super(context);
+ }
+
+ public BaseContactEditorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /**
+ * Assign the given {@link Bitmap} to the internal {@link PhotoEditorView}
+ * for the {@link EntityDelta} currently being edited.
+ */
+ public void setPhotoBitmap(Bitmap bitmap) {
+ mPhoto.setPhotoBitmap(bitmap);
+ }
+
+ /**
+ * Return true if the current {@link RawContacts} supports {@link Photo},
+ * which means that {@link PhotoEditorView} is enabled.
+ */
+ public boolean hasPhotoEditor() {
+ return mHasPhotoEditor;
+ }
+
+ /**
+ * Return true if internal {@link PhotoEditorView} has a {@link Photo} set.
+ */
+ public boolean hasSetPhoto() {
+ return mPhoto.hasSetPhoto();
+ }
+
+ public PhotoEditorView getPhotoEditor() {
+ return mPhoto;
+ }
+
+ /**
+ * @return the RawContact ID that this editor is editing.
+ */
+ public abstract long getRawContactId();
+
+ /**
+ * Set the internal state for this view, given a current
+ * {@link EntityDelta} state and the {@link ContactsSource} that
+ * apply to that state.
+ */
+ public abstract void setState(EntityDelta state, ContactsSource source);
+
+ /**
+ * Sets the {@link EditorListener} on the name field
+ */
+ public abstract void setNameEditorListener(EditorListener listener);
+}
diff --git a/src/com/android/contacts/ui/widget/CheckableImageView.java b/src/com/android/contacts/ui/widget/CheckableImageView.java
new file mode 100644
index 0000000..ff5abc0
--- /dev/null
+++ b/src/com/android/contacts/ui/widget/CheckableImageView.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.ui.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Checkable;
+import android.widget.ImageView;
+
+/**
+ * A special variation of ImageView that can be used as a checkable object.
+ * This is used as the background view of quickcontact chiclet, which is in checked state
+ * when disambig list is shown. Otherwise, it works identically to a ImageView.
+ */
+public class CheckableImageView extends ImageView implements Checkable {
+ private boolean mChecked;
+
+ private static final int[] CHECKED_STATE_SET = {
+ android.R.attr.state_checked
+ };
+
+ public CheckableImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public int[] onCreateDrawableState(int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+ if (isChecked()) {
+ mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+ }
+ return drawableState;
+ }
+
+ public void toggle() {
+ setChecked(!mChecked);
+ }
+
+ public boolean isChecked() {
+ return mChecked;
+ }
+
+ public void setChecked(boolean checked) {
+ if (mChecked != checked) {
+ mChecked = checked;
+ refreshDrawableState();
+ }
+ }
+}
diff --git a/src/com/android/contacts/ui/widget/ContactEditorView.java b/src/com/android/contacts/ui/widget/ContactEditorView.java
new file mode 100644
index 0000000..1720822
--- /dev/null
+++ b/src/com/android/contacts/ui/widget/ContactEditorView.java
@@ -0,0 +1,264 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui.widget;
+
+import com.android.contacts.R;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.Editor.EditorListener;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+
+import android.content.Context;
+import android.content.Entity;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * Custom view that provides all the editor interaction for a specific
+ * {@link Contacts} represented through an {@link EntityDelta}. Callers can
+ * reuse this view and quickly rebuild its contents through
+ * {@link #setState(EntityDelta, ContactsSource)}.
+ * <p>
+ * Internal updates are performed against {@link ValuesDelta} so that the
+ * source {@link Entity} can be swapped out. Any state-based changes, such as
+ * adding {@link Data} rows or changing {@link EditType}, are performed through
+ * {@link EntityModifier} to ensure that {@link ContactsSource} are enforced.
+ */
+public class ContactEditorView extends BaseContactEditorView implements OnClickListener {
+ private TextView mReadOnly;
+ private TextView mReadOnlyName;
+
+ private View mPhotoStub;
+ private GenericEditorView mName;
+
+ private ViewGroup mGeneral;
+ private ViewGroup mSecondary;
+ private boolean mSecondaryVisible;
+
+ private TextView mSecondaryHeader;
+
+ private Drawable mSecondaryOpen;
+ private Drawable mSecondaryClosed;
+
+ private View mHeaderColorBar;
+ private View mSideBar;
+ private ImageView mHeaderIcon;
+ private TextView mHeaderAccountType;
+ private TextView mHeaderAccountName;
+
+ private long mRawContactId = -1;
+
+ public ContactEditorView(Context context) {
+ super(context);
+ }
+
+ public ContactEditorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mInflater = (LayoutInflater)getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ mPhoto = (PhotoEditorView)findViewById(R.id.edit_photo);
+ mPhotoStub = findViewById(R.id.stub_photo);
+
+ final int photoSize = getResources().getDimensionPixelSize(R.dimen.edit_photo_size);
+
+ mReadOnly = (TextView)findViewById(R.id.edit_read_only);
+
+ mName = (GenericEditorView)findViewById(R.id.edit_name);
+ mName.setMinimumHeight(photoSize);
+ mName.setDeletable(false);
+
+ mReadOnlyName = (TextView) findViewById(R.id.read_only_name);
+
+ mGeneral = (ViewGroup)findViewById(R.id.sect_general);
+ mSecondary = (ViewGroup)findViewById(R.id.sect_secondary);
+
+ mHeaderColorBar = findViewById(R.id.header_color_bar);
+ mSideBar = findViewById(R.id.color_bar);
+ mHeaderIcon = (ImageView) findViewById(R.id.header_icon);
+ mHeaderAccountType = (TextView) findViewById(R.id.header_account_type);
+ mHeaderAccountName = (TextView) findViewById(R.id.header_account_name);
+
+ mSecondaryHeader = (TextView)findViewById(R.id.head_secondary);
+ mSecondaryHeader.setOnClickListener(this);
+
+ final Resources res = getResources();
+ mSecondaryOpen = res.getDrawable(com.android.internal.R.drawable.expander_ic_maximized);
+ mSecondaryClosed = res.getDrawable(com.android.internal.R.drawable.expander_ic_minimized);
+
+ this.setSecondaryVisible(false);
+ }
+
+ /** {@inheritDoc} */
+ public void onClick(View v) {
+ // Toggle visibility of secondary kinds
+ final boolean makeVisible = mSecondary.getVisibility() != View.VISIBLE;
+ this.setSecondaryVisible(makeVisible);
+ }
+
+ /**
+ * Set the visibility of secondary sections, along with header icon.
+ */
+ private void setSecondaryVisible(boolean makeVisible) {
+ mSecondary.setVisibility(makeVisible ? View.VISIBLE : View.GONE);
+ mSecondaryHeader.setCompoundDrawablesWithIntrinsicBounds(makeVisible ? mSecondaryOpen
+ : mSecondaryClosed, null, null, null);
+ mSecondaryVisible = makeVisible;
+ }
+
+ /**
+ * Set the internal state for this view, given a current
+ * {@link EntityDelta} state and the {@link ContactsSource} that
+ * apply to that state.
+ */
+ @Override
+ public void setState(EntityDelta state, ContactsSource source) {
+ // Remove any existing sections
+ mGeneral.removeAllViews();
+ mSecondary.removeAllViews();
+
+ // Bail if invalid state or source
+ if (state == null || source == null) return;
+
+ // Make sure we have StructuredName
+ EntityModifier.ensureKindExists(state, source, StructuredName.CONTENT_ITEM_TYPE);
+
+ // Fill in the header info
+ ValuesDelta values = state.getValues();
+ String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
+ CharSequence accountType = source.getDisplayLabel(mContext);
+ if (TextUtils.isEmpty(accountType)) {
+ accountType = mContext.getString(R.string.account_phone);
+ }
+ if (!TextUtils.isEmpty(accountName)) {
+ mHeaderAccountName.setText(
+ mContext.getString(R.string.from_account_format, accountName));
+ }
+ mHeaderAccountType.setText(mContext.getString(R.string.account_type_format, accountType));
+ mHeaderIcon.setImageDrawable(source.getDisplayIcon(mContext));
+
+ mRawContactId = values.getAsLong(RawContacts._ID);
+
+ // Show photo editor when supported
+ EntityModifier.ensureKindExists(state, source, Photo.CONTENT_ITEM_TYPE);
+ mHasPhotoEditor = (source.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null);
+ mPhoto.setVisibility(mHasPhotoEditor ? View.VISIBLE : View.GONE);
+ mPhoto.setEnabled(!source.readOnly);
+ mName.setEnabled(!source.readOnly);
+
+ boolean readOnly = source.readOnly;
+ // Show and hide the appropriate views
+ if (readOnly) {
+ mGeneral.setVisibility(View.GONE);
+ mName.setVisibility(View.GONE);
+ mReadOnly.setVisibility(View.VISIBLE);
+ mReadOnly.setText(mContext.getString(R.string.contact_read_only, accountType));
+ mReadOnlyName.setVisibility(View.VISIBLE);
+ } else {
+ mGeneral.setVisibility(View.VISIBLE);
+ mName.setVisibility(View.VISIBLE);
+ mReadOnly.setVisibility(View.GONE);
+ mReadOnlyName.setVisibility(View.GONE);
+ }
+
+ // Create editor sections for each possible data kind
+ for (DataKind kind : source.getSortedDataKinds()) {
+ // Skip kind of not editable
+ if (!kind.editable) continue;
+
+ final String mimeType = kind.mimeType;
+ if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ // Handle special case editor for structured name
+ final ValuesDelta primary = state.getPrimaryEntry(mimeType);
+ if (!readOnly) {
+ mName.setValues(kind, primary, state, source.readOnly);
+ } else {
+ String displayName = primary.getAsString(StructuredName.DISPLAY_NAME);
+ mReadOnlyName.setText(displayName);
+ }
+ } else if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ // Handle special case editor for photos
+ final ValuesDelta primary = state.getPrimaryEntry(mimeType);
+ mPhoto.setValues(kind, primary, state, source.readOnly);
+ if (readOnly && !mPhoto.hasSetPhoto()) {
+ mPhotoStub.setVisibility(View.GONE);
+ } else {
+ mPhotoStub.setVisibility(View.VISIBLE);
+ }
+ } else if (!readOnly) {
+ // Otherwise use generic section-based editors
+ if (kind.fieldList == null) continue;
+ final ViewGroup parent = kind.secondary ? mSecondary : mGeneral;
+ final KindSectionView section = (KindSectionView)mInflater.inflate(
+ R.layout.item_kind_section, parent, false);
+ section.setState(kind, state, source.readOnly);
+ section.setId(kind.weight);
+ parent.addView(section);
+ }
+ }
+
+ if (!readOnly && mSecondary.getChildCount() > 0) {
+ // There exist secondary elements, show the header and honor mSecondaryVisible
+ mSecondaryHeader.setVisibility(View.VISIBLE);
+ if (mSecondaryVisible) {
+ mSecondary.setVisibility(View.VISIBLE);
+ } else {
+ mSecondary.setVisibility(View.GONE);
+ }
+ } else {
+ // There are no secondary elements, hide the whole thing
+ mSecondaryHeader.setVisibility(View.GONE);
+ mSecondary.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Sets the {@link EditorListener} on the name field
+ */
+ @Override
+ public void setNameEditorListener(EditorListener listener) {
+ mName.setEditorListener(listener);
+ }
+
+ @Override
+ public long getRawContactId() {
+ return mRawContactId;
+ }
+}
diff --git a/src/com/android/contacts/ui/widget/DontPressWithParentImageView.java b/src/com/android/contacts/ui/widget/DontPressWithParentImageView.java
new file mode 100644
index 0000000..bdb0e0a
--- /dev/null
+++ b/src/com/android/contacts/ui/widget/DontPressWithParentImageView.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+
+/**
+ * Special class to to allow the parent to be pressed without being pressed itself.
+ * This way the line of a tab can be pressed, but the image itself is not.
+ */
+public class DontPressWithParentImageView extends ImageView {
+
+ public DontPressWithParentImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void setPressed(boolean pressed) {
+ // If the parent is pressed, do not set to pressed.
+ if (pressed && ((View) getParent()).isPressed()) {
+ return;
+ }
+ super.setPressed(pressed);
+ }
+}
diff --git a/src/com/android/contacts/ui/widget/GenericEditorView.java b/src/com/android/contacts/ui/widget/GenericEditorView.java
new file mode 100644
index 0000000..e1fdd71
--- /dev/null
+++ b/src/com/android/contacts/ui/widget/GenericEditorView.java
@@ -0,0 +1,365 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui.widget;
+
+import com.android.contacts.ContactsUtils;
+import com.android.contacts.R;
+import com.android.contacts.model.Editor;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.model.ContactsSource.EditField;
+import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Entity;
+import android.telephony.PhoneNumberFormattingTextWatcher;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ListAdapter;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import java.util.List;
+
+/**
+ * Simple editor that handles labels and any {@link EditField} defined for
+ * the entry. Uses {@link ValuesDelta} to read any existing
+ * {@link Entity} values, and to correctly write any changes values.
+ */
+public class GenericEditorView extends RelativeLayout implements Editor, View.OnClickListener {
+ protected static final int RES_FIELD = R.layout.item_editor_field;
+ protected static final int RES_LABEL_ITEM = android.R.layout.simple_list_item_1;
+
+ protected LayoutInflater mInflater;
+
+ protected static final int INPUT_TYPE_CUSTOM = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
+
+ protected TextView mLabel;
+ protected ViewGroup mFields;
+ protected View mDelete;
+ protected View mMore;
+
+ protected DataKind mKind;
+ protected ValuesDelta mEntry;
+ protected EntityDelta mState;
+ protected boolean mReadOnly;
+
+ protected boolean mHideOptional = true;
+
+ protected EditType mType;
+ // Used only when a user tries to use custom label.
+ private EditType mPendingType;
+
+ public GenericEditorView(Context context) {
+ super(context);
+ }
+
+ public GenericEditorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onFinishInflate() {
+ mInflater = (LayoutInflater)getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ mLabel = (TextView)findViewById(R.id.edit_label);
+ mLabel.setOnClickListener(this);
+
+ mFields = (ViewGroup)findViewById(R.id.edit_fields);
+
+ mDelete = findViewById(R.id.edit_delete);
+ mDelete.setOnClickListener(this);
+
+ mMore = findViewById(R.id.edit_more);
+ mMore.setOnClickListener(this);
+ }
+
+ protected EditorListener mListener;
+
+ public void setEditorListener(EditorListener listener) {
+ mListener = listener;
+ }
+
+ public void setDeletable(boolean deletable) {
+ mDelete.setVisibility(deletable ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ mLabel.setEnabled(enabled);
+ final int count = mFields.getChildCount();
+ for (int pos = 0; pos < count; pos++) {
+ final View v = mFields.getChildAt(pos);
+ v.setEnabled(enabled);
+ }
+ mMore.setEnabled(enabled);
+ }
+
+ /**
+ * Build the current label state based on selected {@link EditType} and
+ * possible custom label string.
+ */
+ private void rebuildLabel() {
+ // Handle undetected types
+ if (mType == null) {
+ mLabel.setText(R.string.unknown);
+ return;
+ }
+
+ if (mType.customColumn != null) {
+ // Use custom label string when present
+ final String customText = mEntry.getAsString(mType.customColumn);
+ if (customText != null) {
+ mLabel.setText(customText);
+ return;
+ }
+ }
+
+ // Otherwise fall back to using default label
+ mLabel.setText(mType.labelRes);
+ }
+
+ /** {@inheritDoc} */
+ public void onFieldChanged(String column, String value) {
+ // Field changes are saved directly
+ mEntry.put(column, value);
+ if (mListener != null) {
+ mListener.onRequest(EditorListener.FIELD_CHANGED);
+ }
+ }
+
+ private void rebuildValues() {
+ setValues(mKind, mEntry, mState, mReadOnly);
+ }
+
+ /**
+ * Prepare this editor using the given {@link DataKind} for defining
+ * structure and {@link ValuesDelta} describing the content to edit.
+ */
+ public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly) {
+ mKind = kind;
+ mEntry = entry;
+ mState = state;
+ mReadOnly = readOnly;
+
+ final boolean enabled = !readOnly;
+
+ if (!entry.isVisible()) {
+ // Hide ourselves entirely if deleted
+ setVisibility(View.GONE);
+ return;
+ } else {
+ setVisibility(View.VISIBLE);
+ }
+
+ // Display label selector if multiple types available
+ final boolean hasTypes = EntityModifier.hasEditTypes(kind);
+ mLabel.setVisibility(hasTypes ? View.VISIBLE : View.GONE);
+ mLabel.setEnabled(enabled);
+ if (hasTypes) {
+ mType = EntityModifier.getCurrentType(entry, kind);
+ rebuildLabel();
+ }
+
+ // Build out set of fields
+ mFields.removeAllViews();
+ boolean hidePossible = false;
+ for (EditField field : kind.fieldList) {
+ // Inflate field from definition
+ EditText fieldView = (EditText)mInflater.inflate(RES_FIELD, mFields, false);
+ if (field.titleRes > 0) {
+ fieldView.setHint(field.titleRes);
+ }
+ int inputType = field.inputType;
+ fieldView.setInputType(inputType);
+ if (inputType == InputType.TYPE_CLASS_PHONE) {
+ fieldView.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
+ }
+ fieldView.setMinLines(field.minLines);
+
+ // Read current value from state
+ final String column = field.column;
+ final String value = entry.getAsString(column);
+ fieldView.setText(value);
+
+ // Prepare listener for writing changes
+ fieldView.addTextChangedListener(new TextWatcher() {
+ public void afterTextChanged(Editable s) {
+ // Trigger event for newly changed value
+ onFieldChanged(column, s.toString());
+ }
+
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+ });
+
+ // Hide field when empty and optional value
+ final boolean couldHide = (!ContactsUtils.isGraphic(value) && field.optional);
+ final boolean willHide = (mHideOptional && couldHide);
+ fieldView.setVisibility(willHide ? View.GONE : View.VISIBLE);
+ fieldView.setEnabled(enabled);
+ hidePossible = hidePossible || couldHide;
+
+ mFields.addView(fieldView);
+ }
+
+ // When hiding fields, place expandable
+ mMore.setVisibility(hidePossible ? View.VISIBLE : View.GONE);
+ mMore.setEnabled(enabled);
+ }
+
+ /**
+ * Prepare dialog for entering a custom label. The input value is trimmed: white spaces before
+ * and after the input text is removed.
+ * <p>
+ * If the final value is empty, this change request is ignored;
+ * no empty text is allowed in any custom label.
+ */
+ private Dialog createCustomDialog() {
+ final EditText customType = new EditText(mContext);
+ customType.setInputType(INPUT_TYPE_CUSTOM);
+ customType.requestFocus();
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ builder.setTitle(R.string.customLabelPickerTitle);
+ builder.setView(customType);
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ final String customText = customType.getText().toString().trim();
+ if (ContactsUtils.isGraphic(customText)) {
+ // Now we're sure it's ok to actually change the type value.
+ mType = mPendingType;
+ mPendingType = null;
+ mEntry.put(mKind.typeColumn, mType.rawValue);
+ mEntry.put(mType.customColumn, customText);
+ rebuildLabel();
+ }
+ }
+ });
+
+ builder.setNegativeButton(android.R.string.cancel, null);
+
+ return builder.create();
+ }
+
+ /**
+ * Prepare dialog for picking a new {@link EditType} or entering a
+ * custom label. This dialog is limited to the valid types as determined
+ * by {@link EntityModifier}.
+ */
+ public Dialog createLabelDialog() {
+ // Build list of valid types, including the current value
+ final List<EditType> validTypes = EntityModifier.getValidTypes(mState, mKind, mType);
+
+ // Wrap our context to inflate list items using correct theme
+ final Context dialogContext = new ContextThemeWrapper(mContext,
+ android.R.style.Theme_Light);
+ final LayoutInflater dialogInflater = mInflater.cloneInContext(dialogContext);
+
+ final ListAdapter typeAdapter = new ArrayAdapter<EditType>(mContext, RES_LABEL_ITEM,
+ validTypes) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = dialogInflater.inflate(RES_LABEL_ITEM, parent, false);
+ }
+
+ final EditType type = this.getItem(position);
+ final TextView textView = (TextView)convertView;
+ textView.setText(type.labelRes);
+ return textView;
+ }
+ };
+
+ final DialogInterface.OnClickListener clickListener =
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+
+ final EditType selected = validTypes.get(which);
+ if (selected.customColumn != null) {
+ // Show custom label dialog if requested by type.
+ //
+ // Only when the custum value input in the next step is correct one.
+ // this method also set the type value to what the user requested here.
+ mPendingType = selected;
+ createCustomDialog().show();
+ } else {
+ // User picked type, and we're sure it's ok to actually write the entry.
+ mType = selected;
+ mEntry.put(mKind.typeColumn, mType.rawValue);
+ rebuildLabel();
+ }
+ }
+ };
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ builder.setTitle(R.string.selectLabel);
+ builder.setSingleChoiceItems(typeAdapter, 0, clickListener);
+ return builder.create();
+ }
+
+ /** {@inheritDoc} */
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.edit_label: {
+ createLabelDialog().show();
+ break;
+ }
+ case R.id.edit_delete: {
+ // Keep around in model, but mark as deleted
+ mEntry.markDeleted();
+
+ // Remove editor from parent view
+ final ViewGroup parent = (ViewGroup)getParent();
+ parent.removeView(this);
+
+ if (mListener != null) {
+ // Notify listener when present
+ mListener.onDeleted(this);
+ }
+ break;
+ }
+ case R.id.edit_more: {
+ mHideOptional = !mHideOptional;
+ rebuildValues();
+ break;
+ }
+ }
+ }
+}
diff --git a/src/com/android/contacts/ui/widget/KindSectionView.java b/src/com/android/contacts/ui/widget/KindSectionView.java
new file mode 100644
index 0000000..b52cfd0
--- /dev/null
+++ b/src/com/android/contacts/ui/widget/KindSectionView.java
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui.widget;
+
+import com.android.contacts.R;
+import com.android.contacts.model.Editor;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.model.Editor.EditorListener;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+
+import android.content.Context;
+import android.provider.ContactsContract.Data;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Custom view for an entire section of data as segmented by
+ * {@link DataKind} around a {@link Data#MIMETYPE}. This view shows a
+ * section header and a trigger for adding new {@link Data} rows.
+ */
+public class KindSectionView extends LinearLayout implements OnClickListener, EditorListener {
+ private static final String TAG = "KindSectionView";
+
+ private LayoutInflater mInflater;
+
+ private ViewGroup mEditors;
+ private View mAdd;
+ private TextView mTitle;
+
+ private DataKind mKind;
+ private EntityDelta mState;
+ private boolean mReadOnly;
+
+ public KindSectionView(Context context) {
+ super(context);
+ }
+
+ public KindSectionView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onFinishInflate() {
+ mInflater = (LayoutInflater)getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ setDrawingCacheEnabled(true);
+ setAlwaysDrawnWithCacheEnabled(true);
+
+ mEditors = (ViewGroup)findViewById(R.id.kind_editors);
+
+ mAdd = findViewById(R.id.kind_header);
+ mAdd.setOnClickListener(this);
+
+ mTitle = (TextView)findViewById(R.id.kind_title);
+ }
+
+ /** {@inheritDoc} */
+ public void onDeleted(Editor editor) {
+ this.updateAddEnabled();
+ this.updateEditorsVisible();
+ }
+
+ /** {@inheritDoc} */
+ public void onRequest(int request) {
+ // Ignore requests
+ }
+
+ public void setState(DataKind kind, EntityDelta state, boolean readOnly) {
+ mKind = kind;
+ mState = state;
+ mReadOnly = readOnly;
+
+ // TODO: handle resources from remote packages
+ mTitle.setText(kind.titleRes);
+
+ this.rebuildFromState();
+ this.updateAddEnabled();
+ this.updateEditorsVisible();
+ }
+
+ /**
+ * Build editors for all current {@link #mState} rows.
+ */
+ public void rebuildFromState() {
+ // Remove any existing editors
+ mEditors.removeAllViews();
+
+ // Build individual editors for each entry
+ if (!mState.hasMimeEntries(mKind.mimeType)) return;
+ for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) {
+ // Skip entries that aren't visible
+ if (!entry.isVisible()) continue;
+
+ final GenericEditorView editor = (GenericEditorView)mInflater.inflate(
+ R.layout.item_generic_editor, mEditors, false);
+ editor.setValues(mKind, entry, mState, mReadOnly);
+ editor.setEditorListener(this);
+ editor.setId(entry.getViewId());
+ mEditors.addView(editor);
+ }
+ }
+
+ protected void updateEditorsVisible() {
+ final boolean hasChildren = mEditors.getChildCount() > 0;
+ mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE);
+ }
+
+ protected void updateAddEnabled() {
+ // Set enabled state on the "add" view
+ final boolean canInsert = EntityModifier.canInsert(mState, mKind);
+ final boolean isEnabled = !mReadOnly && canInsert;
+ mAdd.setEnabled(isEnabled);
+ }
+
+ /** {@inheritDoc} */
+ public void onClick(View v) {
+ // Insert a new child and rebuild
+ EntityModifier.insertChild(mState, mKind);
+ this.rebuildFromState();
+ this.updateAddEnabled();
+ this.updateEditorsVisible();
+ }
+}
diff --git a/src/com/android/contacts/ui/widget/PhotoEditorView.java b/src/com/android/contacts/ui/widget/PhotoEditorView.java
new file mode 100644
index 0000000..f117091
--- /dev/null
+++ b/src/com/android/contacts/ui/widget/PhotoEditorView.java
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui.widget;
+
+import com.android.contacts.R;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.Editor;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ImageView;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Simple editor for {@link Photo}.
+ */
+public class PhotoEditorView extends ImageView implements Editor, OnClickListener {
+ private static final String TAG = "PhotoEditorView";
+
+ private ValuesDelta mEntry;
+ private EditorListener mListener;
+
+ private boolean mHasSetPhoto = false;
+ private boolean mReadOnly;
+
+ public PhotoEditorView(Context context) {
+ super(context);
+ }
+
+ public PhotoEditorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ this.setOnClickListener(this);
+ }
+
+ /** {@inheritDoc} */
+ public void onClick(View v) {
+ if (mListener != null) {
+ mListener.onRequest(EditorListener.REQUEST_PICK_PHOTO);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void onFieldChanged(String column, String value) {
+ throw new UnsupportedOperationException("Photos don't support direct field changes");
+ }
+
+ /** {@inheritDoc} */
+ public void setValues(DataKind kind, ValuesDelta values, EntityDelta state, boolean readOnly) {
+ mEntry = values;
+ mReadOnly = readOnly;
+ if (values != null) {
+ // Try decoding photo if actual entry
+ final byte[] photoBytes = values.getAsByteArray(Photo.PHOTO);
+ if (photoBytes != null) {
+ final Bitmap photo = BitmapFactory.decodeByteArray(photoBytes, 0,
+ photoBytes.length);
+
+ setScaleType(ImageView.ScaleType.CENTER_CROP);
+ setImageBitmap(photo);
+ setEnabled(true);
+ mHasSetPhoto = true;
+ mEntry.setFromTemplate(false);
+ } else {
+ resetDefault();
+ }
+ } else {
+ resetDefault();
+ }
+ }
+
+ /**
+ * Return true if a valid {@link Photo} has been set.
+ */
+ public boolean hasSetPhoto() {
+ return mHasSetPhoto;
+ }
+
+ /**
+ * Assign the given {@link Bitmap} as the new value, updating UI and
+ * readying for persisting through {@link ValuesDelta}.
+ */
+ public void setPhotoBitmap(Bitmap photo) {
+ if (photo == null) {
+ // Clear any existing photo and return
+ mEntry.put(Photo.PHOTO, (byte[])null);
+ resetDefault();
+ return;
+ }
+
+ final int size = photo.getWidth() * photo.getHeight() * 4;
+ final ByteArrayOutputStream out = new ByteArrayOutputStream(size);
+
+ try {
+ photo.compress(Bitmap.CompressFormat.PNG, 100, out);
+ out.flush();
+ out.close();
+
+ mEntry.put(Photo.PHOTO, out.toByteArray());
+ setImageBitmap(photo);
+ setEnabled(true);
+ mHasSetPhoto = true;
+ mEntry.setFromTemplate(false);
+
+ // When the user chooses a new photo mark it as super primary
+ mEntry.put(Photo.IS_SUPER_PRIMARY, 1);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to serialize photo: " + e.toString());
+ }
+ }
+
+ /**
+ * Set the super primary bit on the photo.
+ */
+ public void setSuperPrimary(boolean superPrimary) {
+ mEntry.put(Photo.IS_SUPER_PRIMARY, superPrimary ? 1 : 0);
+ }
+
+ protected void resetDefault() {
+ // Invalid photo, show default "add photo" place-holder
+ setScaleType(ImageView.ScaleType.CENTER);
+ if (mReadOnly) {
+ setImageResource(R.drawable.ic_contact_picture);
+ setEnabled(false);
+ } else {
+ setImageResource(R.drawable.ic_menu_add_picture);
+ setEnabled(true);
+ }
+ mHasSetPhoto = false;
+ mEntry.setFromTemplate(true);
+ }
+
+ /** {@inheritDoc} */
+ public void setEditorListener(EditorListener listener) {
+ mListener = listener;
+ }
+}
diff --git a/src/com/android/contacts/ui/widget/ReadOnlyContactEditorView.java b/src/com/android/contacts/ui/widget/ReadOnlyContactEditorView.java
new file mode 100644
index 0000000..a5f8eb6
--- /dev/null
+++ b/src/com/android/contacts/ui/widget/ReadOnlyContactEditorView.java
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.ui.widget;
+
+import com.android.contacts.R;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.Editor.EditorListener;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+
+import android.content.Context;
+import android.content.Entity;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * Custom view that displays read-only contacts in the edit screen.
+ */
+class ReadOnlyContactEditorView extends BaseContactEditorView {
+
+ private View mPhotoStub;
+ private TextView mName;
+ private TextView mReadOnlyWarning;
+ private ViewGroup mGeneral;
+
+ private View mHeaderColorBar;
+ private View mSideBar;
+ private ImageView mHeaderIcon;
+ private TextView mHeaderAccountType;
+ private TextView mHeaderAccountName;
+
+ private long mRawContactId = -1;
+
+ public ReadOnlyContactEditorView(Context context) {
+ super(context);
+ }
+
+ public ReadOnlyContactEditorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mInflater = (LayoutInflater)getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ mPhoto = (PhotoEditorView)findViewById(R.id.edit_photo);
+ mPhotoStub = findViewById(R.id.stub_photo);
+
+ mName = (TextView) findViewById(R.id.read_only_name);
+ mReadOnlyWarning = (TextView) findViewById(R.id.read_only_warning);
+ mGeneral = (ViewGroup)findViewById(R.id.sect_general);
+
+ mHeaderColorBar = findViewById(R.id.header_color_bar);
+ mSideBar = findViewById(R.id.color_bar);
+ mHeaderIcon = (ImageView) findViewById(R.id.header_icon);
+ mHeaderAccountType = (TextView) findViewById(R.id.header_account_type);
+ mHeaderAccountName = (TextView) findViewById(R.id.header_account_name);
+ }
+
+ /**
+ * Set the internal state for this view, given a current
+ * {@link EntityDelta} state and the {@link ContactsSource} that
+ * apply to that state.
+ *
+ * TODO: make this more generic using data from the source
+ */
+ @Override
+ public void setState(EntityDelta state, ContactsSource source) {
+ // Remove any existing sections
+ mGeneral.removeAllViews();
+
+ // Bail if invalid state or source
+ if (state == null || source == null) return;
+
+ // Make sure we have StructuredName
+ EntityModifier.ensureKindExists(state, source, StructuredName.CONTENT_ITEM_TYPE);
+
+ // Fill in the header info
+ ValuesDelta values = state.getValues();
+ String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
+ CharSequence accountType = source.getDisplayLabel(mContext);
+ if (TextUtils.isEmpty(accountType)) {
+ accountType = mContext.getString(R.string.account_phone);
+ }
+ if (!TextUtils.isEmpty(accountName)) {
+ mHeaderAccountName.setText(
+ mContext.getString(R.string.from_account_format, accountName));
+ }
+ mHeaderAccountType.setText(mContext.getString(R.string.account_type_format, accountType));
+ mHeaderIcon.setImageDrawable(source.getDisplayIcon(mContext));
+
+ mRawContactId = values.getAsLong(RawContacts._ID);
+
+ ValuesDelta primary;
+
+ // Photo
+ DataKind kind = source.getKindForMimetype(Photo.CONTENT_ITEM_TYPE);
+ if (kind != null) {
+ EntityModifier.ensureKindExists(state, source, Photo.CONTENT_ITEM_TYPE);
+ mHasPhotoEditor = (source.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null);
+ primary = state.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
+ mPhoto.setValues(kind, primary, state, source.readOnly);
+ if (!mHasPhotoEditor || !mPhoto.hasSetPhoto()) {
+ mPhotoStub.setVisibility(View.GONE);
+ } else {
+ mPhotoStub.setVisibility(View.VISIBLE);
+ }
+ } else {
+ mPhotoStub.setVisibility(View.VISIBLE);
+ }
+
+ // Name
+ primary = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
+ mName.setText(primary.getAsString(StructuredName.DISPLAY_NAME));
+
+ // Read only warning
+ mReadOnlyWarning.setText(mContext.getString(R.string.contact_read_only, accountType));
+
+ // Phones
+ ArrayList<ValuesDelta> phones = state.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
+ if (phones != null) {
+ for (ValuesDelta phone : phones) {
+ View field = mInflater.inflate(
+ R.layout.item_read_only_field, mGeneral, false);
+ TextView v;
+ v = (TextView) field.findViewById(R.id.label);
+ v.setText(mContext.getText(R.string.phoneLabelsGroup));
+ v = (TextView) field.findViewById(R.id.data);
+ v.setText(PhoneNumberUtils.formatNumber(phone.getAsString(Phone.NUMBER)));
+ mGeneral.addView(field);
+ }
+ }
+
+ // Emails
+ ArrayList<ValuesDelta> emails = state.getMimeEntries(Email.CONTENT_ITEM_TYPE);
+ if (emails != null) {
+ for (ValuesDelta email : emails) {
+ View field = mInflater.inflate(
+ R.layout.item_read_only_field, mGeneral, false);
+ TextView v;
+ v = (TextView) field.findViewById(R.id.label);
+ v.setText(mContext.getText(R.string.emailLabelsGroup));
+ v = (TextView) field.findViewById(R.id.data);
+ v.setText(email.getAsString(Email.DATA));
+ mGeneral.addView(field);
+ }
+ }
+
+ // Hide mGeneral if it's empty
+ if (mGeneral.getChildCount() > 0) {
+ mGeneral.setVisibility(View.VISIBLE);
+ } else {
+ mGeneral.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Sets the {@link EditorListener} on the name field
+ */
+ @Override
+ public void setNameEditorListener(EditorListener listener) {
+ // do nothing
+ }
+
+ @Override
+ public long getRawContactId() {
+ return mRawContactId;
+ }
+}
diff --git a/src/com/android/contacts/util/AccountSelectionUtil.java b/src/com/android/contacts/util/AccountSelectionUtil.java
new file mode 100644
index 0000000..cf83581
--- /dev/null
+++ b/src/com/android/contacts/util/AccountSelectionUtil.java
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.util;
+
+import com.android.contacts.ImportVCardActivity;
+import com.android.contacts.R;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.GoogleSource;
+import com.android.contacts.model.Sources;
+
+import android.accounts.Account;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import java.util.List;
+
+/**
+ * Utility class for selectiong an Account for importing contact(s)
+ */
+public class AccountSelectionUtil {
+ // TODO: maybe useful for EditContactActivity.java...
+ private static final String LOG_TAG = "AccountSelectionUtil";
+
+ private static class AccountSelectedListener
+ implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+
+ final private Context mContext;
+ final private List<Account> mAccountList;
+ final private int mResId;
+
+ public AccountSelectedListener(Context context, List<Account> accountList, int resId) {
+ if (accountList == null || accountList.size() == 0) {
+ Log.e(LOG_TAG, "The size of Account list is 0.");
+ }
+ mContext = context;
+ mAccountList = accountList;
+ mResId = resId;
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ doImport(mContext, mResId, mAccountList.get(which));
+ }
+
+ public void onCancel(DialogInterface dialog) {
+ dialog.dismiss();
+ }
+ }
+
+ public static Dialog getSelectAccountDialog(Context context, int resId) {
+ return getSelectAccountDialog(context, resId, null);
+ }
+
+ public static Dialog getSelectAccountDialog(Context context, int resId,
+ DialogInterface.OnCancelListener onCancelListener) {
+ final Sources sources = Sources.getInstance(context);
+ final List<Account> writableAccountList = sources.getAccounts(true);
+
+ // Assume accountList.size() > 1
+
+ // Wrap our context to inflate list items using correct theme
+ final Context dialogContext = new ContextThemeWrapper(
+ context, android.R.style.Theme_Light);
+ final LayoutInflater dialogInflater = (LayoutInflater)dialogContext
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ final ArrayAdapter<Account> accountAdapter =
+ new ArrayAdapter<Account>(context, android.R.layout.simple_list_item_2,
+ writableAccountList) {
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = dialogInflater.inflate(
+ android.R.layout.simple_list_item_2,
+ parent, false);
+ }
+
+ // TODO: show icon along with title
+ final TextView text1 =
+ (TextView)convertView.findViewById(android.R.id.text1);
+ final TextView text2 =
+ (TextView)convertView.findViewById(android.R.id.text2);
+
+ final Account account = this.getItem(position);
+ final ContactsSource source =
+ sources.getInflatedSource(account.type,
+ ContactsSource.LEVEL_SUMMARY);
+ final Context context = getContext();
+
+ text1.setText(account.name);
+ text2.setText(source.getDisplayLabel(context));
+
+ return convertView;
+ }
+ };
+
+ AccountSelectedListener accountSelectedListener =
+ new AccountSelectedListener(context, writableAccountList, resId);
+ return new AlertDialog.Builder(context)
+ .setTitle(R.string.dialog_new_contact_account)
+ .setSingleChoiceItems(accountAdapter, 0, accountSelectedListener)
+ .setOnCancelListener(accountSelectedListener)
+ .create();
+ }
+
+ public static void doImport(Context context, int resId, Account account) {
+ switch (resId) {
+ case R.string.import_from_sim: {
+ doImportFromSim(context, account);
+ break;
+ }
+ case R.string.import_from_sdcard: {
+ doImportFromSdCard(context, account);
+ break;
+ }
+ }
+ }
+
+ public static void doImportFromSim(Context context, Account account) {
+ if (account != null) {
+ GoogleSource.createMyContactsIfNotExist(account, context);
+ }
+
+ Intent importIntent = new Intent(Intent.ACTION_VIEW);
+ importIntent.setType("vnd.android.cursor.item/sim-contact");
+ if (account != null) {
+ importIntent.putExtra("account_name", account.name);
+ importIntent.putExtra("account_type", account.type);
+ }
+ importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
+ context.startActivity(importIntent);
+ }
+
+ public static void doImportFromSdCard(Context context, Account account) {
+ if (account != null) {
+ GoogleSource.createMyContactsIfNotExist(account, context);
+ }
+
+ Intent importIntent = new Intent(context, ImportVCardActivity.class);
+ if (account != null) {
+ importIntent.putExtra("account_name", account.name);
+ importIntent.putExtra("account_type", account.type);
+ }
+ context.startActivity(importIntent);
+ }
+}
diff --git a/src/com/android/contacts/util/Constants.java b/src/com/android/contacts/util/Constants.java
new file mode 100644
index 0000000..e0178ad
--- /dev/null
+++ b/src/com/android/contacts/util/Constants.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.util;
+
+import android.app.Service;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+
+/**
+ * Background {@link Service} that is used to keep our process alive long enough
+ * for background threads to finish. Started and stopped directly by specific
+ * background tasks when needed.
+ */
+public class Constants {
+ /**
+ * Specific MIME-type for {@link Phone#CONTENT_ITEM_TYPE} entries that
+ * distinguishes actions that should initiate a text message.
+ */
+ public static final String MIME_SMS_ADDRESS = "vnd.android.cursor.item/sms-address";
+
+ public static final String SCHEME_TEL = "tel";
+ public static final String SCHEME_SMSTO = "smsto";
+ public static final String SCHEME_MAILTO = "mailto";
+ public static final String SCHEME_IMTO = "imto";
+
+}
diff --git a/src/com/android/contacts/util/DataStatus.java b/src/com/android/contacts/util/DataStatus.java
new file mode 100644
index 0000000..88c6594
--- /dev/null
+++ b/src/com/android/contacts/util/DataStatus.java
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.util;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.provider.ContactsContract.Data;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+
+/**
+ * Storage for a social status update. Holds a single update, but can use
+ * {@link #possibleUpdate(Cursor)} to consider updating when a better status
+ * exists. Statuses with timestamps, or with newer timestamps win.
+ */
+public class DataStatus {
+ private int mPresence = -1;
+ private String mStatus = null;
+ private long mTimestamp = -1;
+
+ private String mResPackage = null;
+ private int mIconRes = -1;
+ private int mLabelRes = -1;
+
+ public DataStatus() {
+ }
+
+ public DataStatus(Cursor cursor) {
+ // When creating from cursor row, fill normally
+ fromCursor(cursor);
+ }
+
+ /**
+ * Attempt updating this {@link DataStatus} based on values at the
+ * current row of the given {@link Cursor}.
+ */
+ public void possibleUpdate(Cursor cursor) {
+ final boolean hasStatus = !isNull(cursor, Data.STATUS);
+ final boolean hasTimestamp = !isNull(cursor, Data.STATUS_TIMESTAMP);
+
+ // Bail early when not valid status, or when previous status was
+ // found and we can't compare this one.
+ if (!hasStatus) return;
+ if (isValid() && !hasTimestamp) return;
+
+ if (hasTimestamp) {
+ // Compare timestamps and bail if older status
+ final long newTimestamp = getLong(cursor, Data.STATUS_TIMESTAMP, -1);
+ if (newTimestamp < mTimestamp) return;
+
+ mTimestamp = newTimestamp;
+ }
+
+ // Fill in remaining details from cursor
+ fromCursor(cursor);
+ }
+
+ private void fromCursor(Cursor cursor) {
+ mPresence = getInt(cursor, Data.PRESENCE, -1);
+ mStatus = getString(cursor, Data.STATUS);
+ mTimestamp = getLong(cursor, Data.STATUS_TIMESTAMP, -1);
+ mResPackage = getString(cursor, Data.STATUS_RES_PACKAGE);
+ mIconRes = getInt(cursor, Data.STATUS_ICON, -1);
+ mLabelRes = getInt(cursor, Data.STATUS_LABEL, -1);
+ }
+
+ public boolean isValid() {
+ return !TextUtils.isEmpty(mStatus);
+ }
+
+ public int getPresence() {
+ return mPresence;
+ }
+
+ public CharSequence getStatus() {
+ return mStatus;
+ }
+
+ /**
+ * Build any timestamp and label into a single string.
+ */
+ public CharSequence getTimestampLabel(Context context) {
+ final PackageManager pm = context.getPackageManager();
+
+ // Use local package for resources when none requested
+ if (mResPackage == null) mResPackage = context.getPackageName();
+
+ final boolean validTimestamp = mTimestamp > 0;
+ final boolean validLabel = mResPackage != null && mLabelRes != -1;
+
+ final CharSequence timeClause = validTimestamp ? DateUtils.getRelativeTimeSpanString(
+ mTimestamp, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,
+ DateUtils.FORMAT_ABBREV_RELATIVE) : null;
+ final CharSequence labelClause = validLabel ? pm.getText(mResPackage, mLabelRes,
+ null) : null;
+
+ if (validTimestamp && validLabel) {
+ return context.getString(
+ com.android.internal.R.string.contact_status_update_attribution_with_date,
+ timeClause, labelClause);
+ } else if (validLabel) {
+ return context.getString(
+ com.android.internal.R.string.contact_status_update_attribution,
+ labelClause);
+ } else if (validTimestamp) {
+ return timeClause;
+ } else {
+ return null;
+ }
+ }
+
+ public Drawable getIcon(Context context) {
+ final PackageManager pm = context.getPackageManager();
+
+ // Use local package for resources when none requested
+ if (mResPackage == null) mResPackage = context.getPackageName();
+
+ final boolean validIcon = mResPackage != null && mIconRes != -1;
+ return validIcon ? pm.getDrawable(mResPackage, mIconRes, null) : null;
+ }
+
+ private static String getString(Cursor cursor, String columnName) {
+ return cursor.getString(cursor.getColumnIndex(columnName));
+ }
+
+ private static int getInt(Cursor cursor, String columnName) {
+ return cursor.getInt(cursor.getColumnIndex(columnName));
+ }
+
+ private static int getInt(Cursor cursor, String columnName, int missingValue) {
+ final int columnIndex = cursor.getColumnIndex(columnName);
+ return cursor.isNull(columnIndex) ? missingValue : cursor.getInt(columnIndex);
+ }
+
+ private static long getLong(Cursor cursor, String columnName, long missingValue) {
+ final int columnIndex = cursor.getColumnIndex(columnName);
+ return cursor.isNull(columnIndex) ? missingValue : cursor.getLong(columnIndex);
+ }
+
+ private static boolean isNull(Cursor cursor, String columnName) {
+ return cursor.isNull(cursor.getColumnIndex(columnName));
+ }
+}
diff --git a/src/com/android/contacts/util/EmptyService.java b/src/com/android/contacts/util/EmptyService.java
new file mode 100644
index 0000000..2e6a159
--- /dev/null
+++ b/src/com/android/contacts/util/EmptyService.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.util;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Background {@link Service} that is used to keep our process alive long enough
+ * for background threads to finish. Started and stopped directly by specific
+ * background tasks when needed.
+ */
+public class EmptyService extends Service {
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java b/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
new file mode 100644
index 0000000..795ac79
--- /dev/null
+++ b/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.util;
+
+import android.content.AsyncQueryHandler;
+import android.content.Context;
+import android.content.EntityIterator;
+import android.database.Cursor;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Slightly more abstract {@link AsyncQueryHandler} that helps keep a
+ * {@link WeakReference} back to a listener. Will properly close any
+ * {@link Cursor} or {@link EntityIterator} if the listener ceases to exist.
+ * <p>
+ * This pattern can be used to perform background queries without leaking
+ * {@link Context} objects.
+ *
+ * @hide pending API council review
+ */
+public class NotifyingAsyncQueryHandler extends AsyncQueryHandler {
+ private WeakReference<AsyncQueryListener> mListener;
+
+ /**
+ * Interface to listen for completed query operations.
+ */
+ public interface AsyncQueryListener {
+ void onQueryComplete(int token, Object cookie, Cursor cursor);
+ void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator);
+ }
+
+ public NotifyingAsyncQueryHandler(Context context, AsyncQueryListener listener) {
+ super(context.getContentResolver());
+ setQueryListener(listener);
+ }
+
+ /**
+ * Assign the given {@link AsyncQueryListener} to receive query events from
+ * asynchronous calls. Will replace any existing listener.
+ */
+ public void setQueryListener(AsyncQueryListener listener) {
+ mListener = new WeakReference<AsyncQueryListener>(listener);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ final AsyncQueryListener listener = mListener.get();
+ if (listener != null) {
+ listener.onQueryComplete(token, cookie, cursor);
+ } else if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
+ final AsyncQueryListener listener = mListener.get();
+ if (listener != null) {
+ listener.onQueryEntitiesComplete(token, cookie, iterator);
+ } else if (iterator != null) {
+ iterator.close();
+ }
+ }
+}
diff --git a/src/com/android/contacts/util/WeakAsyncTask.java b/src/com/android/contacts/util/WeakAsyncTask.java
new file mode 100644
index 0000000..f60cfd7
--- /dev/null
+++ b/src/com/android/contacts/util/WeakAsyncTask.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts.util;
+
+import android.os.AsyncTask;
+
+import java.lang.ref.WeakReference;
+
+public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget> extends
+ AsyncTask<Params, Progress, Result> {
+ protected WeakReference<WeakTarget> mTarget;
+
+ public WeakAsyncTask(WeakTarget target) {
+ mTarget = new WeakReference<WeakTarget>(target);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected final void onPreExecute() {
+ final WeakTarget target = mTarget.get();
+ if (target != null) {
+ this.onPreExecute(target);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected final Result doInBackground(Params... params) {
+ final WeakTarget target = mTarget.get();
+ if (target != null) {
+ return this.doInBackground(target, params);
+ } else {
+ return null;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected final void onPostExecute(Result result) {
+ final WeakTarget target = mTarget.get();
+ if (target != null) {
+ this.onPostExecute(target, result);
+ }
+ }
+
+ protected void onPreExecute(WeakTarget target) {
+ // No default action
+ }
+
+ protected abstract Result doInBackground(WeakTarget target, Params... params);
+
+ protected void onPostExecute(WeakTarget target, Result result) {
+ // No default action
+ }
+}
diff --git a/tests/Android.mk b/tests/Android.mk
index 47782e3..ef11c5e 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -3,7 +3,7 @@
# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
-LOCAL_CERTIFICATE := platform
+LOCAL_CERTIFICATE := shared
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index ca28a6a..7f845f9 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -19,11 +19,12 @@
<application>
<uses-library android:name="android.test.runner" />
+ <meta-data android:name="com.android.contacts.iconset" android:resource="@xml/iconset" />
</application>
- <instrumentation android:name="ContactsLaunchPerformance"
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.contacts"
- android:label="Contacts Launch Performance">
+ android:label="Contacts app tests">
</instrumentation>
</manifest>
diff --git a/tests/res/drawable/default_icon.png b/tests/res/drawable/default_icon.png
new file mode 100644
index 0000000..cea0eb3
--- /dev/null
+++ b/tests/res/drawable/default_icon.png
Binary files differ
diff --git a/tests/res/drawable/phone_icon.png b/tests/res/drawable/phone_icon.png
new file mode 100644
index 0000000..4e613ec
--- /dev/null
+++ b/tests/res/drawable/phone_icon.png
Binary files differ
diff --git a/tests/res/xml/iconset.xml b/tests/res/xml/iconset.xml
new file mode 100644
index 0000000..d910815
--- /dev/null
+++ b/tests/res/xml/iconset.xml
@@ -0,0 +1,8 @@
+<icon-set
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <icon-default android:icon="@drawable/default_icon" />
+ <icon android:mimeType="vnd.android.cursor.item/phone"
+ android:icon="@drawable/phone_icon" />
+
+</icon-set>
\ No newline at end of file
diff --git a/tests/src/com/android/contacts/ContactsLaunchPerformance.java b/tests/src/com/android/contacts/ContactsLaunchPerformance.java
index 85dba56..bd60e70 100644
--- a/tests/src/com/android/contacts/ContactsLaunchPerformance.java
+++ b/tests/src/com/android/contacts/ContactsLaunchPerformance.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.tests;
+package com.android.contacts;
import android.app.Activity;
import android.test.LaunchPerformanceBase;
diff --git a/tests/src/com/android/contacts/ContactsUtilsTests.java b/tests/src/com/android/contacts/ContactsUtilsTests.java
new file mode 100644
index 0000000..01a1ef4
--- /dev/null
+++ b/tests/src/com/android/contacts/ContactsUtilsTests.java
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import android.content.ContentValues;
+import android.content.Intent;
+import android.net.Uri;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+/**
+ * Tests for {@link ContactsUtils}.
+ */
+@LargeTest
+public class ContactsUtilsTests extends AndroidTestCase {
+ private static final String TEST_ADDRESS = "user@example.org";
+ private static final String TEST_PROTOCOL = "prot%col";
+
+ public void testImIntent() throws Exception {
+ // Normal IM is appended as path
+ final ContentValues values = new ContentValues();
+ values.put(Im.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ values.put(Im.TYPE, Im.TYPE_HOME);
+ values.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
+ values.put(Im.DATA, TEST_ADDRESS);
+
+ final Intent intent = ContactsUtils.buildImIntent(values);
+ assertEquals(Intent.ACTION_SENDTO, intent.getAction());
+
+ final Uri data = intent.getData();
+ assertEquals("imto", data.getScheme());
+ assertEquals("gtalk", data.getAuthority());
+ assertEquals(TEST_ADDRESS, data.getPathSegments().get(0));
+ }
+
+ public void testImIntentCustom() throws Exception {
+ // Custom IM types have encoded authority
+ final ContentValues values = new ContentValues();
+ values.put(Im.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ values.put(Im.TYPE, Im.TYPE_HOME);
+ values.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM);
+ values.put(Im.CUSTOM_PROTOCOL, TEST_PROTOCOL);
+ values.put(Im.DATA, TEST_ADDRESS);
+
+ final Intent intent = ContactsUtils.buildImIntent(values);
+ assertEquals(Intent.ACTION_SENDTO, intent.getAction());
+
+ final Uri data = intent.getData();
+ assertEquals("imto", data.getScheme());
+ assertEquals(TEST_PROTOCOL, data.getAuthority());
+ assertEquals(TEST_ADDRESS, data.getPathSegments().get(0));
+ }
+
+ public void testImEmailIntent() throws Exception {
+ // Email addresses are treated as Google Talk entries
+ final ContentValues values = new ContentValues();
+ values.put(Email.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ values.put(Email.TYPE, Email.TYPE_HOME);
+ values.put(Email.DATA, TEST_ADDRESS);
+
+ final Intent intent = ContactsUtils.buildImIntent(values);
+ assertEquals(Intent.ACTION_SENDTO, intent.getAction());
+
+ final Uri data = intent.getData();
+ assertEquals("imto", data.getScheme());
+ assertEquals("gtalk", data.getAuthority());
+ assertEquals(TEST_ADDRESS, data.getPathSegments().get(0));
+ }
+
+ public void testIsGraphicNull() throws Exception {
+ assertFalse(ContactsUtils.isGraphic(null));
+ }
+
+ public void testIsGraphicEmpty() throws Exception {
+ assertFalse(ContactsUtils.isGraphic(""));
+ }
+
+ public void testIsGraphicSpaces() throws Exception {
+ assertFalse(ContactsUtils.isGraphic(" "));
+ }
+
+ public void testIsGraphicPunctuation() throws Exception {
+ assertTrue(ContactsUtils.isGraphic("."));
+ }
+}
diff --git a/tests/src/com/android/contacts/EntityDeltaTests.java b/tests/src/com/android/contacts/EntityDeltaTests.java
new file mode 100644
index 0000000..70a506b
--- /dev/null
+++ b/tests/src/com/android/contacts/EntityDeltaTests.java
@@ -0,0 +1,411 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.google.android.collect.Lists;
+
+import static android.content.ContentProviderOperation.TYPE_INSERT;
+import static android.content.ContentProviderOperation.TYPE_UPDATE;
+import static android.content.ContentProviderOperation.TYPE_DELETE;
+import static android.content.ContentProviderOperation.TYPE_ASSERT;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.content.Entity;
+import android.content.ContentProviderOperation.Builder;
+import android.os.Parcel;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for {@link EntityDelta} and {@link ValuesDelta}. These tests
+ * focus on passing changes across {@link Parcel}, and verifying that they
+ * correctly build expected "diff" operations.
+ */
+@LargeTest
+public class EntityDeltaTests extends AndroidTestCase {
+ public static final String TAG = "EntityDeltaTests";
+
+ public static final long TEST_CONTACT_ID = 12;
+ public static final long TEST_PHONE_ID = 24;
+
+ public static final String TEST_PHONE_NUMBER_1 = "218-555-1111";
+ public static final String TEST_PHONE_NUMBER_2 = "218-555-2222";
+
+ public static final String TEST_ACCOUNT_NAME = "TEST";
+
+ public EntityDeltaTests() {
+ super();
+ }
+
+ @Override
+ public void setUp() {
+ mContext = getContext();
+ }
+
+ public static Entity getEntity(long contactId, long phoneId) {
+ // Build an existing contact read from database
+ final ContentValues contact = new ContentValues();
+ contact.put(RawContacts.VERSION, 43);
+ contact.put(RawContacts._ID, contactId);
+
+ final ContentValues phone = new ContentValues();
+ phone.put(Data._ID, phoneId);
+ phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
+ phone.put(Phone.TYPE, Phone.TYPE_HOME);
+
+ final Entity before = new Entity(contact);
+ before.addSubValue(Data.CONTENT_URI, phone);
+ return before;
+ }
+
+ /**
+ * Test that {@link EntityDelta#mergeAfter(EntityDelta)} correctly passes
+ * any changes through the {@link Parcel} object. This enforces that
+ * {@link EntityDelta} should be identical when serialized against the same
+ * "before" {@link Entity}.
+ */
+ public void testParcelChangesNone() {
+ final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
+ final EntityDelta source = EntityDelta.fromBefore(before);
+ final EntityDelta dest = EntityDelta.fromBefore(before);
+
+ // Merge modified values and assert they match
+ final EntityDelta merged = EntityDelta.mergeAfter(dest, source);
+ assertEquals("Unexpected change when merging", source, merged);
+ }
+
+ public void testParcelChangesInsert() {
+ final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
+ final EntityDelta source = EntityDelta.fromBefore(before);
+ final EntityDelta dest = EntityDelta.fromBefore(before);
+
+ // Add a new row and pass across parcel, should be same
+ final ContentValues phone = new ContentValues();
+ phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
+ phone.put(Phone.TYPE, Phone.TYPE_WORK);
+ source.addEntry(ValuesDelta.fromAfter(phone));
+
+ // Merge modified values and assert they match
+ final EntityDelta merged = EntityDelta.mergeAfter(dest, source);
+ assertEquals("Unexpected change when merging", source, merged);
+ }
+
+ public void testParcelChangesUpdate() {
+ // Update existing row and pass across parcel, should be same
+ final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
+ final EntityDelta source = EntityDelta.fromBefore(before);
+ final EntityDelta dest = EntityDelta.fromBefore(before);
+
+ final ValuesDelta child = source.getEntry(TEST_PHONE_ID);
+ child.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
+
+ // Merge modified values and assert they match
+ final EntityDelta merged = EntityDelta.mergeAfter(dest, source);
+ assertEquals("Unexpected change when merging", source, merged);
+ }
+
+ public void testParcelChangesDelete() {
+ // Delete a row and pass across parcel, should be same
+ final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
+ final EntityDelta source = EntityDelta.fromBefore(before);
+ final EntityDelta dest = EntityDelta.fromBefore(before);
+
+ final ValuesDelta child = source.getEntry(TEST_PHONE_ID);
+ child.markDeleted();
+
+ // Merge modified values and assert they match
+ final EntityDelta merged = EntityDelta.mergeAfter(dest, source);
+ assertEquals("Unexpected change when merging", source, merged);
+ }
+
+ /**
+ * Test that {@link ValuesDelta#buildDiff(android.net.Uri)} is correctly
+ * built for insert, update, and delete cases. Note this only tests behavior
+ * for individual {@link Data} rows.
+ */
+ public void testValuesDiffNone() {
+ final ContentValues before = new ContentValues();
+ before.put(Data._ID, TEST_PHONE_ID);
+ before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
+
+ final ValuesDelta values = ValuesDelta.fromBefore(before);
+
+ // None action shouldn't produce a builder
+ final Builder builder = values.buildDiff(Data.CONTENT_URI);
+ assertNull("None action produced a builder", builder);
+ }
+
+ public void testValuesDiffInsert() {
+ final ContentValues after = new ContentValues();
+ after.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
+
+ final ValuesDelta values = ValuesDelta.fromAfter(after);
+
+ // Should produce an insert action
+ final Builder builder = values.buildDiff(Data.CONTENT_URI);
+ final int type = builder.build().getType();
+ assertEquals("Didn't produce insert action", TYPE_INSERT, type);
+ }
+
+ public void testValuesDiffUpdate() {
+ final ContentValues before = new ContentValues();
+ before.put(Data._ID, TEST_PHONE_ID);
+ before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
+
+ final ValuesDelta values = ValuesDelta.fromBefore(before);
+ values.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
+
+ // Should produce an update action
+ final Builder builder = values.buildDiff(Data.CONTENT_URI);
+ final int type = builder.build().getType();
+ assertEquals("Didn't produce update action", TYPE_UPDATE, type);
+ }
+
+ public void testValuesDiffDelete() {
+ final ContentValues before = new ContentValues();
+ before.put(Data._ID, TEST_PHONE_ID);
+ before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
+
+ final ValuesDelta values = ValuesDelta.fromBefore(before);
+ values.markDeleted();
+
+ // Should produce a delete action
+ final Builder builder = values.buildDiff(Data.CONTENT_URI);
+ final int type = builder.build().getType();
+ assertEquals("Didn't produce delete action", TYPE_DELETE, type);
+ }
+
+ /**
+ * Test that {@link EntityDelta#buildDiff(ArrayList)} is correctly built for
+ * insert, update, and delete cases. This only tests a subset of possible
+ * {@link Data} row changes.
+ */
+ public void testEntityDiffNone() {
+ final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
+ final EntityDelta source = EntityDelta.fromBefore(before);
+
+ // Assert that writing unchanged produces few operations
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ source.buildDiff(diff);
+
+ assertTrue("Created changes when none needed", (diff.size() == 0));
+ }
+
+ public void testEntityDiffNoneInsert() {
+ final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
+ final EntityDelta source = EntityDelta.fromBefore(before);
+
+ // Insert a new phone number
+ final ContentValues phone = new ContentValues();
+ phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
+ phone.put(Phone.TYPE, Phone.TYPE_WORK);
+ source.addEntry(ValuesDelta.fromAfter(phone));
+
+ // Assert two operations: insert Data row and enforce version
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ source.buildAssert(diff);
+ source.buildDiff(diff);
+ assertEquals("Unexpected operations", 4, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected version enforcement", TYPE_ASSERT, oper.getType());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(3);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testEntityDiffUpdateInsert() {
+ final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
+ final EntityDelta source = EntityDelta.fromBefore(before);
+
+ // Update parent contact values
+ source.getValues().put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
+
+ // Insert a new phone number
+ final ContentValues phone = new ContentValues();
+ phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
+ phone.put(Phone.TYPE, Phone.TYPE_WORK);
+ source.addEntry(ValuesDelta.fromAfter(phone));
+
+ // Assert three operations: update Contact, insert Data row, enforce version
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ source.buildAssert(diff);
+ source.buildDiff(diff);
+ assertEquals("Unexpected operations", 5, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected version enforcement", TYPE_ASSERT, oper.getType());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(3);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(4);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testEntityDiffNoneUpdate() {
+ final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
+ final EntityDelta source = EntityDelta.fromBefore(before);
+
+ // Update existing phone number
+ final ValuesDelta child = source.getEntry(TEST_PHONE_ID);
+ child.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
+
+ // Assert that version is enforced
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ source.buildAssert(diff);
+ source.buildDiff(diff);
+ assertEquals("Unexpected operations", 4, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected version enforcement", TYPE_ASSERT, oper.getType());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(3);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testEntityDiffDelete() {
+ final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
+ final EntityDelta source = EntityDelta.fromBefore(before);
+
+ // Delete entire entity
+ source.getValues().markDeleted();
+
+ // Assert two operations: delete Contact and enforce version
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ source.buildAssert(diff);
+ source.buildDiff(diff);
+ assertEquals("Unexpected operations", 2, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected version enforcement", TYPE_ASSERT, oper.getType());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testEntityDiffInsert() {
+ // Insert a RawContact
+ final ContentValues after = new ContentValues();
+ after.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
+ after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
+
+ final ValuesDelta values = ValuesDelta.fromAfter(after);
+ final EntityDelta source = new EntityDelta(values);
+
+ // Assert two operations: delete Contact and enforce version
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ source.buildAssert(diff);
+ source.buildDiff(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testEntityDiffInsertInsert() {
+ // Insert a RawContact
+ final ContentValues after = new ContentValues();
+ after.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
+ after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
+
+ final ValuesDelta values = ValuesDelta.fromAfter(after);
+ final EntityDelta source = new EntityDelta(values);
+
+ // Insert a new phone number
+ final ContentValues phone = new ContentValues();
+ phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
+ phone.put(Phone.TYPE, Phone.TYPE_WORK);
+ source.addEntry(ValuesDelta.fromAfter(phone));
+
+ // Assert two operations: delete Contact and enforce version
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ source.buildAssert(diff);
+ source.buildDiff(diff);
+ assertEquals("Unexpected operations", 2, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/EntityModifierTests.java b/tests/src/com/android/contacts/EntityModifierTests.java
new file mode 100644
index 0000000..489bf04
--- /dev/null
+++ b/tests/src/com/android/contacts/EntityModifierTests.java
@@ -0,0 +1,665 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import static android.content.ContentProviderOperation.TYPE_DELETE;
+import static android.content.ContentProviderOperation.TYPE_INSERT;
+import static android.content.ContentProviderOperation.TYPE_UPDATE;
+
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.EntitySet;
+import com.android.contacts.model.Sources;
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.google.android.collect.Lists;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Entity;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link EntityModifier} to verify that {@link ContactsSource}
+ * constraints are being enforced correctly.
+ */
+@LargeTest
+public class EntityModifierTests extends AndroidTestCase {
+ public static final String TAG = "EntityModifierTests";
+
+ public static final long VER_FIRST = 100;
+
+ private static final long TEST_ID = 4;
+ private static final String TEST_PHONE = "218-555-1212";
+
+ private static final String TEST_ACCOUNT_NAME = "unittest@example.com";
+ private static final String TEST_ACCOUNT_TYPE = "com.example.unittest";
+
+ public EntityModifierTests() {
+ super();
+ }
+
+ @Override
+ public void setUp() {
+ mContext = getContext();
+ }
+
+ public static class MockContactsSource extends ContactsSource {
+ @Override
+ protected void inflate(Context context, int inflateLevel) {
+ this.accountType = TEST_ACCOUNT_TYPE;
+ this.setInflatedLevel(ContactsSource.LEVEL_CONSTRAINTS);
+
+ // Phone allows maximum 2 home, 1 work, and unlimited other, with
+ // constraint of 5 numbers maximum.
+ DataKind kind = new DataKind(Phone.CONTENT_ITEM_TYPE, -1, -1, 10, true);
+
+ kind.typeOverallMax = 5;
+ kind.typeColumn = Phone.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(new EditType(Phone.TYPE_HOME, -1).setSpecificMax(2));
+ kind.typeList.add(new EditType(Phone.TYPE_WORK, -1).setSpecificMax(1));
+ kind.typeList.add(new EditType(Phone.TYPE_FAX_WORK, -1).setSecondary(true));
+ kind.typeList.add(new EditType(Phone.TYPE_OTHER, -1));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Phone.NUMBER, -1, -1));
+ kind.fieldList.add(new EditField(Phone.LABEL, -1, -1));
+
+ addKind(kind);
+
+ // Email is unlimited
+ kind = new DataKind(Email.CONTENT_ITEM_TYPE, -1, -1, 10, true);
+
+ kind.typeOverallMax = -1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Email.DATA, -1, -1));
+
+ addKind(kind);
+ }
+
+ @Override
+ public int getHeaderColor(Context context) {
+ return 0;
+ }
+
+ @Override
+ public int getSideBarColor(Context context) {
+ return 0xffffff;
+ }
+ }
+
+ /**
+ * Build a {@link ContactsSource} that has various odd constraints for
+ * testing purposes.
+ */
+ protected ContactsSource getSource() {
+ final ContactsSource source = new MockContactsSource();
+ source.ensureInflated(getContext(), ContactsSource.LEVEL_CONSTRAINTS);
+ return source;
+ }
+
+ /**
+ * Build {@link Sources} instance.
+ */
+ protected Sources getSources(ContactsSource... sources) {
+ return new Sources(sources);
+ }
+
+ /**
+ * Build an {@link Entity} with the requested set of phone numbers.
+ */
+ protected EntityDelta getEntity(Long existingId, ContentValues... entries) {
+ final ContentValues contact = new ContentValues();
+ if (existingId != null) {
+ contact.put(RawContacts._ID, existingId);
+ }
+ contact.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
+ contact.put(RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE);
+
+ final Entity before = new Entity(contact);
+ for (ContentValues values : entries) {
+ before.addSubValue(Data.CONTENT_URI, values);
+ }
+ return EntityDelta.fromBefore(before);
+ }
+
+ /**
+ * Assert this {@link List} contains the given {@link Object}.
+ */
+ protected void assertContains(List<?> list, Object object) {
+ assertTrue("Missing expected value", list.contains(object));
+ }
+
+ /**
+ * Assert this {@link List} does not contain the given {@link Object}.
+ */
+ protected void assertNotContains(List<?> list, Object object) {
+ assertFalse("Contained unexpected value", list.contains(object));
+ }
+
+ /**
+ * Insert various rows to test
+ * {@link EntityModifier#getValidTypes(EntityDelta, DataKind, EditType)}
+ */
+ public void testValidTypes() {
+ // Build a source and pull specific types
+ final ContactsSource source = getSource();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeWork = EntityModifier.getType(kindPhone, Phone.TYPE_WORK);
+ final EditType typeOther = EntityModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+ List<EditType> validTypes;
+
+ // Add first home, first work
+ final EntityDelta state = getEntity(TEST_ID);
+ EntityModifier.insertChild(state, kindPhone, typeHome);
+ EntityModifier.insertChild(state, kindPhone, typeWork);
+
+ // Expecting home, other
+ validTypes = EntityModifier.getValidTypes(state, kindPhone, null);
+ assertContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertContains(validTypes, typeOther);
+
+ // Add second home
+ EntityModifier.insertChild(state, kindPhone, typeHome);
+
+ // Expecting other
+ validTypes = EntityModifier.getValidTypes(state, kindPhone, null);
+ assertNotContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertContains(validTypes, typeOther);
+
+ // Add third and fourth home (invalid, but possible)
+ EntityModifier.insertChild(state, kindPhone, typeHome);
+ EntityModifier.insertChild(state, kindPhone, typeHome);
+
+ // Expecting none
+ validTypes = EntityModifier.getValidTypes(state, kindPhone, null);
+ assertNotContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertNotContains(validTypes, typeOther);
+ }
+
+ /**
+ * Test {@link EntityModifier#canInsert(EntityDelta, DataKind)} by
+ * inserting various rows.
+ */
+ public void testCanInsert() {
+ // Build a source and pull specific types
+ final ContactsSource source = getSource();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeWork = EntityModifier.getType(kindPhone, Phone.TYPE_WORK);
+ final EditType typeOther = EntityModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+ // Add first home, first work
+ final EntityDelta state = getEntity(TEST_ID);
+ EntityModifier.insertChild(state, kindPhone, typeHome);
+ EntityModifier.insertChild(state, kindPhone, typeWork);
+ assertTrue("Unable to insert", EntityModifier.canInsert(state, kindPhone));
+
+ // Add two other, which puts us just under "5" overall limit
+ EntityModifier.insertChild(state, kindPhone, typeOther);
+ EntityModifier.insertChild(state, kindPhone, typeOther);
+ assertTrue("Unable to insert", EntityModifier.canInsert(state, kindPhone));
+
+ // Add second home, which should push to snug limit
+ EntityModifier.insertChild(state, kindPhone, typeHome);
+ assertFalse("Able to insert", EntityModifier.canInsert(state, kindPhone));
+ }
+
+ /**
+ * Test
+ * {@link EntityModifier#getBestValidType(EntityDelta, DataKind, boolean, int)}
+ * by asserting expected best options in various states.
+ */
+ public void testBestValidType() {
+ // Build a source and pull specific types
+ final ContactsSource source = getSource();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeWork = EntityModifier.getType(kindPhone, Phone.TYPE_WORK);
+ final EditType typeFaxWork = EntityModifier.getType(kindPhone, Phone.TYPE_FAX_WORK);
+ final EditType typeOther = EntityModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+ EditType suggested;
+
+ // Default suggestion should be home
+ final EntityDelta state = getEntity(TEST_ID);
+ suggested = EntityModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeHome, suggested);
+
+ // Add first home, should now suggest work
+ EntityModifier.insertChild(state, kindPhone, typeHome);
+ suggested = EntityModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeWork, suggested);
+
+ // Add work fax, should still suggest work
+ EntityModifier.insertChild(state, kindPhone, typeFaxWork);
+ suggested = EntityModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeWork, suggested);
+
+ // Add other, should still suggest work
+ EntityModifier.insertChild(state, kindPhone, typeOther);
+ suggested = EntityModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeWork, suggested);
+
+ // Add work, now should suggest other
+ EntityModifier.insertChild(state, kindPhone, typeWork);
+ suggested = EntityModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeOther, suggested);
+ }
+
+ public void testIsEmptyEmpty() {
+ final ContactsSource source = getSource();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+
+ // Test entirely empty row
+ final ContentValues after = new ContentValues();
+ final ValuesDelta values = ValuesDelta.fromAfter(after);
+
+ assertTrue("Expected empty", EntityModifier.isEmpty(values, kindPhone));
+ }
+
+ public void testIsEmptyDirectFields() {
+ final ContactsSource source = getSource();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values, but core fields are empty
+ final EntityDelta state = getEntity(TEST_ID);
+ final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+
+ assertTrue("Expected empty", EntityModifier.isEmpty(values, kindPhone));
+
+ // Insert some data to trigger non-empty state
+ values.put(Phone.NUMBER, TEST_PHONE);
+
+ assertFalse("Expected non-empty", EntityModifier.isEmpty(values, kindPhone));
+ }
+
+ public void testTrimEmptySingle() {
+ final ContactsSource source = getSource();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values, but core fields are empty
+ final EntityDelta state = getEntity(TEST_ID);
+ final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+
+ // Build diff, expecting insert for data row and update enforcement
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Trim empty rows and try again, expecting delete of overall contact
+ EntityModifier.trimEmpty(state, source);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testTrimEmptySpaces() {
+ final ContactsSource source = getSource();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values, but values are spaces
+ final EntityDelta state = EntitySetTests.buildBeforeEntity(TEST_ID, VER_FIRST);
+ final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+ values.put(Phone.NUMBER, " ");
+
+ // Build diff, expecting insert for data row and update enforcement
+ EntitySetTests.assertDiffPattern(state,
+ EntitySetTests.buildAssertVersion(VER_FIRST),
+ EntitySetTests.buildUpdateAggregationSuspended(),
+ EntitySetTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
+ EntitySetTests.buildDataInsert(values, TEST_ID)),
+ EntitySetTests.buildUpdateAggregationDefault());
+
+ // Trim empty rows and try again, expecting delete of overall contact
+ EntityModifier.trimEmpty(state, source);
+ EntitySetTests.assertDiffPattern(state,
+ EntitySetTests.buildAssertVersion(VER_FIRST),
+ EntitySetTests.buildDelete(RawContacts.CONTENT_URI));
+ }
+
+ public void testTrimLeaveValid() {
+ final ContactsSource source = getSource();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values with valid number
+ final EntityDelta state = EntitySetTests.buildBeforeEntity(TEST_ID, VER_FIRST);
+ final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+ values.put(Phone.NUMBER, TEST_PHONE);
+
+ // Build diff, expecting insert for data row and update enforcement
+ EntitySetTests.assertDiffPattern(state,
+ EntitySetTests.buildAssertVersion(VER_FIRST),
+ EntitySetTests.buildUpdateAggregationSuspended(),
+ EntitySetTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
+ EntitySetTests.buildDataInsert(values, TEST_ID)),
+ EntitySetTests.buildUpdateAggregationDefault());
+
+ // Trim empty rows and try again, expecting no differences
+ EntityModifier.trimEmpty(state, source);
+ EntitySetTests.assertDiffPattern(state,
+ EntitySetTests.buildAssertVersion(VER_FIRST),
+ EntitySetTests.buildUpdateAggregationSuspended(),
+ EntitySetTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
+ EntitySetTests.buildDataInsert(values, TEST_ID)),
+ EntitySetTests.buildUpdateAggregationDefault());
+ }
+
+ public void testTrimEmptyUntouched() {
+ final ContactsSource source = getSource();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Build "before" that has empty row
+ final EntityDelta state = getEntity(TEST_ID);
+ final ContentValues before = new ContentValues();
+ before.put(Data._ID, TEST_ID);
+ before.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ state.addEntry(ValuesDelta.fromBefore(before));
+
+ // Build diff, expecting no changes
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+
+ // Try trimming existing empty, which we shouldn't touch
+ EntityModifier.trimEmpty(state, source);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+ }
+
+ public void testTrimEmptyAfterUpdate() {
+ final ContactsSource source = getSource();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Build "before" that has row with some phone number
+ final ContentValues before = new ContentValues();
+ before.put(Data._ID, TEST_ID);
+ before.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ before.put(kindPhone.typeColumn, typeHome.rawValue);
+ before.put(Phone.NUMBER, TEST_PHONE);
+ final EntityDelta state = getEntity(TEST_ID, before);
+
+ // Build diff, expecting no changes
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+
+ // Now update row by changing number to empty string, expecting single update
+ final ValuesDelta child = state.getEntry(TEST_ID);
+ child.put(Phone.NUMBER, "");
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Now run trim, which should turn that update into delete
+ EntityModifier.trimEmpty(state, source);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testTrimInsertEmpty() {
+ final ContactsSource source = getSource();
+ final Sources sources = getSources(source);
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Try creating a contact without any child entries
+ final EntityDelta state = getEntity(null);
+ final EntitySet set = EntitySet.fromSingle(state);
+
+ // Build diff, expecting single insert
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Trim empty rows and try again, expecting no insert
+ EntityModifier.trimEmpty(set, sources);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+ }
+
+ public void testTrimInsertInsert() {
+ final ContactsSource source = getSource();
+ final Sources sources = getSources(source);
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Try creating a contact with single empty entry
+ final EntityDelta state = getEntity(null);
+ final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+ final EntitySet set = EntitySet.fromSingle(state);
+
+ // Build diff, expecting two insert operations
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 2, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+
+ // Trim empty rows and try again, expecting silence
+ EntityModifier.trimEmpty(set, sources);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+ }
+
+ public void testTrimUpdateRemain() {
+ final ContactsSource source = getSource();
+ final Sources sources = getSources(source);
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Build "before" with two phone numbers
+ final ContentValues first = new ContentValues();
+ first.put(Data._ID, TEST_ID);
+ first.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ first.put(kindPhone.typeColumn, typeHome.rawValue);
+ first.put(Phone.NUMBER, TEST_PHONE);
+
+ final ContentValues second = new ContentValues();
+ second.put(Data._ID, TEST_ID);
+ second.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ second.put(kindPhone.typeColumn, typeHome.rawValue);
+ second.put(Phone.NUMBER, TEST_PHONE);
+
+ final EntityDelta state = getEntity(TEST_ID, first, second);
+ final EntitySet set = EntitySet.fromSingle(state);
+
+ // Build diff, expecting no changes
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+
+ // Now update row by changing number to empty string, expecting single update
+ final ValuesDelta child = state.getEntry(TEST_ID);
+ child.put(Phone.NUMBER, "");
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Now run trim, which should turn that update into delete
+ EntityModifier.trimEmpty(set, sources);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testTrimUpdateUpdate() {
+ final ContactsSource source = getSource();
+ final Sources sources = getSources(source);
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Build "before" with two phone numbers
+ final ContentValues first = new ContentValues();
+ first.put(Data._ID, TEST_ID);
+ first.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ first.put(kindPhone.typeColumn, typeHome.rawValue);
+ first.put(Phone.NUMBER, TEST_PHONE);
+
+ final EntityDelta state = getEntity(TEST_ID, first);
+ final EntitySet set = EntitySet.fromSingle(state);
+
+ // Build diff, expecting no changes
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+
+ // Now update row by changing number to empty string, expecting single update
+ final ValuesDelta child = state.getEntry(TEST_ID);
+ child.put(Phone.NUMBER, "");
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(1);
+ assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final ContentProviderOperation oper = diff.get(2);
+ assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Now run trim, which should turn into deleting the whole contact
+ EntityModifier.trimEmpty(set, sources);
+ diff.clear();
+ state.buildDiff(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final ContentProviderOperation oper = diff.get(0);
+ assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/EntitySetTests.java b/tests/src/com/android/contacts/EntitySetTests.java
new file mode 100644
index 0000000..26f4184
--- /dev/null
+++ b/tests/src/com/android/contacts/EntitySetTests.java
@@ -0,0 +1,589 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import static android.content.ContentProviderOperation.TYPE_ASSERT;
+import static android.content.ContentProviderOperation.TYPE_DELETE;
+import static android.content.ContentProviderOperation.TYPE_INSERT;
+import static android.content.ContentProviderOperation.TYPE_UPDATE;
+
+import com.android.contacts.EntityModifierTests.MockContactsSource;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.EntitySet;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.google.android.collect.Lists;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.content.Entity;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.provider.ContactsContract.AggregationExceptions;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+
+/**
+ * Tests for {@link EntitySet} which focus on "diff" operations that should
+ * create {@link AggregationExceptions} in certain cases.
+ */
+@LargeTest
+public class EntitySetTests extends AndroidTestCase {
+ public static final String TAG = "EntitySetTests";
+
+ private static final long CONTACT_FIRST = 1;
+ private static final long CONTACT_SECOND = 2;
+
+ public static final long CONTACT_BOB = 10;
+ public static final long CONTACT_MARY = 11;
+
+ public static final long PHONE_RED = 20;
+ public static final long PHONE_GREEN = 21;
+ public static final long PHONE_BLUE = 22;
+
+ public static final long EMAIL_YELLOW = 25;
+
+ public static final long VER_FIRST = 100;
+ public static final long VER_SECOND = 200;
+
+ public static final String TEST_PHONE = "555-1212";
+ public static final String TEST_ACCOUNT = "org.example.test";
+
+ public EntitySetTests() {
+ super();
+ }
+
+ @Override
+ public void setUp() {
+ mContext = getContext();
+ }
+
+ /**
+ * Build a {@link ContactsSource} that has various odd constraints for
+ * testing purposes.
+ */
+ protected ContactsSource getSource() {
+ final ContactsSource source = new MockContactsSource();
+ source.ensureInflated(getContext(), ContactsSource.LEVEL_CONSTRAINTS);
+ return source;
+ }
+
+ static ContentValues getValues(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = ContentProviderOperation.class.getDeclaredField("mValues");
+ field.setAccessible(true);
+ return (ContentValues) field.get(operation);
+ }
+
+ static EntityDelta getUpdate(long rawContactId) {
+ final Entity before = EntityDeltaTests.getEntity(rawContactId,
+ EntityDeltaTests.TEST_PHONE_ID);
+ return EntityDelta.fromBefore(before);
+ }
+
+ static EntityDelta getInsert() {
+ final ContentValues after = new ContentValues();
+ after.put(RawContacts.ACCOUNT_NAME, EntityDeltaTests.TEST_ACCOUNT_NAME);
+ after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
+
+ final ValuesDelta values = ValuesDelta.fromAfter(after);
+ return new EntityDelta(values);
+ }
+
+ static EntitySet buildSet(EntityDelta... deltas) {
+ final EntitySet set = EntitySet.fromSingle(deltas[0]);
+ for (int i = 1; i < deltas.length; i++) {
+ set.add(deltas[i]);
+ }
+ return set;
+ }
+
+ static EntityDelta buildBeforeEntity(long rawContactId, long version,
+ ContentValues... entries) {
+ // Build an existing contact read from database
+ final ContentValues contact = new ContentValues();
+ contact.put(RawContacts.VERSION, version);
+ contact.put(RawContacts._ID, rawContactId);
+ final Entity before = new Entity(contact);
+ for (ContentValues entry : entries) {
+ before.addSubValue(Data.CONTENT_URI, entry);
+ }
+ return EntityDelta.fromBefore(before);
+ }
+
+ static EntityDelta buildAfterEntity(ContentValues... entries) {
+ // Build an existing contact read from database
+ final ContentValues contact = new ContentValues();
+ contact.put(RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT);
+ final EntityDelta after = new EntityDelta(ValuesDelta.fromAfter(contact));
+ for (ContentValues entry : entries) {
+ after.addEntry(ValuesDelta.fromAfter(entry));
+ }
+ return after;
+ }
+
+ static ContentValues buildPhone(long phoneId) {
+ return buildPhone(phoneId, Long.toString(phoneId));
+ }
+
+ static ContentValues buildPhone(long phoneId, String value) {
+ final ContentValues values = new ContentValues();
+ values.put(Data._ID, phoneId);
+ values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ values.put(Phone.NUMBER, value);
+ values.put(Phone.TYPE, Phone.TYPE_HOME);
+ return values;
+ }
+
+ static ContentValues buildEmail(long emailId) {
+ final ContentValues values = new ContentValues();
+ values.put(Data._ID, emailId);
+ values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ values.put(Email.DATA, Long.toString(emailId));
+ values.put(Email.TYPE, Email.TYPE_HOME);
+ return values;
+ }
+
+ static void insertPhone(EntitySet set, long rawContactId, ContentValues values) {
+ final EntityDelta match = set.getByRawContactId(rawContactId);
+ match.addEntry(ValuesDelta.fromAfter(values));
+ }
+
+ static ValuesDelta getPhone(EntitySet set, long rawContactId, long dataId) {
+ final EntityDelta match = set.getByRawContactId(rawContactId);
+ return match.getEntry(dataId);
+ }
+
+ static void assertDiffPattern(EntityDelta delta, ContentProviderOperation... pattern) {
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+ delta.buildAssert(diff);
+ delta.buildDiff(diff);
+ assertDiffPattern(diff, pattern);
+ }
+
+ static void assertDiffPattern(EntitySet set, ContentProviderOperation... pattern) {
+ assertDiffPattern(set.buildDiff(), pattern);
+ }
+
+ static void assertDiffPattern(ArrayList<ContentProviderOperation> diff,
+ ContentProviderOperation... pattern) {
+ assertEquals("Unexpected operations", pattern.length, diff.size());
+ for (int i = 0; i < pattern.length; i++) {
+ final ContentProviderOperation expected = pattern[i];
+ final ContentProviderOperation found = diff.get(i);
+
+ assertEquals("Unexpected uri", expected.getUri(), found.getUri());
+
+ final String expectedType = getStringForType(expected.getType());
+ final String foundType = getStringForType(found.getType());
+ assertEquals("Unexpected type", expectedType, foundType);
+
+ if (expected.getType() == TYPE_DELETE) continue;
+
+ try {
+ final ContentValues expectedValues = getValues(expected);
+ final ContentValues foundValues = getValues(found);
+
+ expectedValues.remove(BaseColumns._ID);
+ foundValues.remove(BaseColumns._ID);
+
+ assertEquals("Unexpected values", expectedValues, foundValues);
+ } catch (NoSuchFieldException e) {
+ fail(e.toString());
+ } catch (IllegalAccessException e) {
+ fail(e.toString());
+ }
+ }
+ }
+
+ static String getStringForType(int type) {
+ switch (type) {
+ case TYPE_ASSERT: return "TYPE_ASSERT";
+ case TYPE_INSERT: return "TYPE_INSERT";
+ case TYPE_UPDATE: return "TYPE_UPDATE";
+ case TYPE_DELETE: return "TYPE_DELETE";
+ default: return Integer.toString(type);
+ }
+ }
+
+ static ContentProviderOperation buildAssertVersion(long version) {
+ final ContentValues values = new ContentValues();
+ values.put(RawContacts.VERSION, version);
+ return buildOper(RawContacts.CONTENT_URI, TYPE_ASSERT, values);
+ }
+
+ static ContentProviderOperation buildAggregationModeUpdate(int mode) {
+ final ContentValues values = new ContentValues();
+ values.put(RawContacts.AGGREGATION_MODE, mode);
+ return buildOper(RawContacts.CONTENT_URI, TYPE_UPDATE, values);
+ }
+
+ static ContentProviderOperation buildUpdateAggregationSuspended() {
+ return buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_SUSPENDED);
+ }
+
+ static ContentProviderOperation buildUpdateAggregationDefault() {
+ return buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT);
+ }
+
+ static ContentProviderOperation buildUpdateAggregationKeepTogether(long rawContactId) {
+ final ContentValues values = new ContentValues();
+ values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId);
+ values.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
+ return buildOper(AggregationExceptions.CONTENT_URI, TYPE_UPDATE, values);
+ }
+
+ static ContentValues buildDataInsert(ValuesDelta values, long rawContactId) {
+ final ContentValues insertValues = values.getCompleteValues();
+ insertValues.put(Data.RAW_CONTACT_ID, rawContactId);
+ return insertValues;
+ }
+
+ static ContentProviderOperation buildDelete(Uri uri) {
+ return buildOper(uri, TYPE_DELETE, (ContentValues)null);
+ }
+
+ static ContentProviderOperation buildOper(Uri uri, int type, ValuesDelta values) {
+ return buildOper(uri, type, values.getCompleteValues());
+ }
+
+ static ContentProviderOperation buildOper(Uri uri, int type, ContentValues values) {
+ switch (type) {
+ case TYPE_ASSERT:
+ return ContentProviderOperation.newAssertQuery(uri).withValues(values).build();
+ case TYPE_INSERT:
+ return ContentProviderOperation.newInsert(uri).withValues(values).build();
+ case TYPE_UPDATE:
+ return ContentProviderOperation.newUpdate(uri).withValues(values).build();
+ case TYPE_DELETE:
+ return ContentProviderOperation.newDelete(uri).build();
+ }
+ return null;
+ }
+
+ static Long getVersion(EntitySet set, Long rawContactId) {
+ return set.getByRawContactId(rawContactId).getValues().getAsLong(RawContacts.VERSION);
+ }
+
+ /**
+ * Count number of {@link AggregationExceptions} updates contained in the
+ * given list of {@link ContentProviderOperation}.
+ */
+ static int countExceptionUpdates(ArrayList<ContentProviderOperation> diff) {
+ int updateCount = 0;
+ for (ContentProviderOperation oper : diff) {
+ if (AggregationExceptions.CONTENT_URI.equals(oper.getUri())
+ && oper.getType() == ContentProviderOperation.TYPE_UPDATE) {
+ updateCount++;
+ }
+ }
+ return updateCount;
+ }
+
+ public void testInsert() {
+ final EntityDelta insert = getInsert();
+ final EntitySet set = buildSet(insert);
+
+ // Inserting single shouldn't create rules
+ final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+ final int exceptionCount = countExceptionUpdates(diff);
+ assertEquals("Unexpected exception updates", 0, exceptionCount);
+ }
+
+ public void testUpdateUpdate() {
+ final EntityDelta updateFirst = getUpdate(CONTACT_FIRST);
+ final EntityDelta updateSecond = getUpdate(CONTACT_SECOND);
+ final EntitySet set = buildSet(updateFirst, updateSecond);
+
+ // Updating two existing shouldn't create rules
+ final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+ final int exceptionCount = countExceptionUpdates(diff);
+ assertEquals("Unexpected exception updates", 0, exceptionCount);
+ }
+
+ public void testUpdateInsert() {
+ final EntityDelta update = getUpdate(CONTACT_FIRST);
+ final EntityDelta insert = getInsert();
+ final EntitySet set = buildSet(update, insert);
+
+ // New insert should only create one rule
+ final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+ final int exceptionCount = countExceptionUpdates(diff);
+ assertEquals("Unexpected exception updates", 1, exceptionCount);
+ }
+
+ public void testInsertUpdateInsert() {
+ final EntityDelta insertFirst = getInsert();
+ final EntityDelta update = getUpdate(CONTACT_FIRST);
+ final EntityDelta insertSecond = getInsert();
+ final EntitySet set = buildSet(insertFirst, update, insertSecond);
+
+ // Two inserts should create two rules to bind against single existing
+ final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+ final int exceptionCount = countExceptionUpdates(diff);
+ assertEquals("Unexpected exception updates", 2, exceptionCount);
+ }
+
+ public void testInsertInsertInsert() {
+ final EntityDelta insertFirst = getInsert();
+ final EntityDelta insertSecond = getInsert();
+ final EntityDelta insertThird = getInsert();
+ final EntitySet set = buildSet(insertFirst, insertSecond, insertThird);
+
+ // Three new inserts should create only two binding rules
+ final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+ final int exceptionCount = countExceptionUpdates(diff);
+ assertEquals("Unexpected exception updates", 2, exceptionCount);
+ }
+
+ public void testMergeDataRemoteInsert() {
+ final EntitySet first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
+ buildPhone(PHONE_RED)));
+ final EntitySet second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
+ buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
+
+ // Merge in second version, verify they match
+ final EntitySet merged = EntitySet.mergeAfter(second, first);
+ assertEquals("Unexpected change when merging", second, merged);
+ }
+
+ public void testMergeDataLocalUpdateRemoteInsert() {
+ final EntitySet first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
+ buildPhone(PHONE_RED)));
+ final EntitySet second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
+ buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
+
+ // Change the local number to trigger update
+ final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
+ phone.put(Phone.NUMBER, TEST_PHONE);
+
+ assertDiffPattern(first,
+ buildAssertVersion(VER_FIRST),
+ buildUpdateAggregationSuspended(),
+ buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
+ buildUpdateAggregationDefault());
+
+ // Merge in the second version, verify diff matches
+ final EntitySet merged = EntitySet.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildUpdateAggregationSuspended(),
+ buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
+ buildUpdateAggregationDefault());
+ }
+
+ public void testMergeDataLocalUpdateRemoteDelete() {
+ final EntitySet first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
+ buildPhone(PHONE_RED)));
+ final EntitySet second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
+ buildPhone(PHONE_GREEN)));
+
+ // Change the local number to trigger update
+ final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
+ phone.put(Phone.NUMBER, TEST_PHONE);
+
+ assertDiffPattern(first,
+ buildAssertVersion(VER_FIRST),
+ buildUpdateAggregationSuspended(),
+ buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
+ buildUpdateAggregationDefault());
+
+ // Merge in the second version, verify that our update changed to
+ // insert, since RED was deleted on remote side
+ final EntitySet merged = EntitySet.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildUpdateAggregationSuspended(),
+ buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(phone, CONTACT_BOB)),
+ buildUpdateAggregationDefault());
+ }
+
+ public void testMergeDataLocalDeleteRemoteUpdate() {
+ final EntitySet first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
+ buildPhone(PHONE_RED)));
+ final EntitySet second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
+ buildPhone(PHONE_RED, TEST_PHONE)));
+
+ // Delete phone locally
+ final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
+ phone.markDeleted();
+
+ assertDiffPattern(first,
+ buildAssertVersion(VER_FIRST),
+ buildUpdateAggregationSuspended(),
+ buildDelete(Data.CONTENT_URI),
+ buildUpdateAggregationDefault());
+
+ // Merge in the second version, verify that our delete remains
+ final EntitySet merged = EntitySet.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildUpdateAggregationSuspended(),
+ buildDelete(Data.CONTENT_URI),
+ buildUpdateAggregationDefault());
+ }
+
+ public void testMergeDataLocalInsertRemoteInsert() {
+ final EntitySet first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
+ buildPhone(PHONE_RED)));
+ final EntitySet second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
+ buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
+
+ // Insert new phone locally
+ final ValuesDelta bluePhone = ValuesDelta.fromAfter(buildPhone(PHONE_BLUE));
+ first.getByRawContactId(CONTACT_BOB).addEntry(bluePhone);
+ assertDiffPattern(first,
+ buildAssertVersion(VER_FIRST),
+ buildUpdateAggregationSuspended(),
+ buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bluePhone, CONTACT_BOB)),
+ buildUpdateAggregationDefault());
+
+ // Merge in the second version, verify that our insert remains
+ final EntitySet merged = EntitySet.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildUpdateAggregationSuspended(),
+ buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bluePhone, CONTACT_BOB)),
+ buildUpdateAggregationDefault());
+ }
+
+ public void testMergeRawContactLocalInsertRemoteInsert() {
+ final EntitySet first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
+ buildPhone(PHONE_RED)));
+ final EntitySet second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
+ buildPhone(PHONE_RED)), buildBeforeEntity(CONTACT_MARY, VER_SECOND,
+ buildPhone(PHONE_RED)));
+
+ // Add new contact locally, should remain insert
+ final ContentValues joePhoneInsert = buildPhone(PHONE_BLUE);
+ final EntityDelta joeContact = buildAfterEntity(joePhoneInsert);
+ final ContentValues joeContactInsert = joeContact.getValues().getCompleteValues();
+ first.add(joeContact);
+ assertDiffPattern(first,
+ buildAssertVersion(VER_FIRST),
+ buildOper(RawContacts.CONTENT_URI, TYPE_INSERT, joeContactInsert),
+ buildOper(Data.CONTENT_URI, TYPE_INSERT, joePhoneInsert),
+ buildUpdateAggregationKeepTogether(CONTACT_BOB));
+
+ // Merge in the second version, verify that our insert remains
+ final EntitySet merged = EntitySet.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildAssertVersion(VER_SECOND),
+ buildOper(RawContacts.CONTENT_URI, TYPE_INSERT, joeContactInsert),
+ buildOper(Data.CONTENT_URI, TYPE_INSERT, joePhoneInsert),
+ buildUpdateAggregationKeepTogether(CONTACT_BOB));
+ }
+
+ public void testMergeRawContactLocalDeleteRemoteDelete() {
+ final EntitySet first = buildSet(
+ buildBeforeEntity(CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
+ buildBeforeEntity(CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
+ final EntitySet second = buildSet(
+ buildBeforeEntity(CONTACT_BOB, VER_SECOND, buildPhone(PHONE_RED)));
+
+ // Remove contact locally
+ first.getByRawContactId(CONTACT_MARY).markDeleted();
+ assertDiffPattern(first,
+ buildAssertVersion(VER_FIRST),
+ buildAssertVersion(VER_FIRST),
+ buildDelete(RawContacts.CONTENT_URI));
+
+ // Merge in the second version, verify that our delete isn't needed
+ final EntitySet merged = EntitySet.mergeAfter(second, first);
+ assertDiffPattern(merged);
+ }
+
+ public void testMergeRawContactLocalUpdateRemoteDelete() {
+ final EntitySet first = buildSet(
+ buildBeforeEntity(CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
+ buildBeforeEntity(CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
+ final EntitySet second = buildSet(
+ buildBeforeEntity(CONTACT_BOB, VER_SECOND, buildPhone(PHONE_RED)));
+
+ // Perform local update
+ final ValuesDelta phone = getPhone(first, CONTACT_MARY, PHONE_RED);
+ phone.put(Phone.NUMBER, TEST_PHONE);
+ assertDiffPattern(first,
+ buildAssertVersion(VER_FIRST),
+ buildAssertVersion(VER_FIRST),
+ buildUpdateAggregationSuspended(),
+ buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
+ buildUpdateAggregationDefault());
+
+ final ContentValues phoneInsert = phone.getCompleteValues();
+ final ContentValues contactInsert = first.getByRawContactId(CONTACT_MARY).getValues()
+ .getCompleteValues();
+
+ // Merge and verify that update turned into insert
+ final EntitySet merged = EntitySet.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildOper(RawContacts.CONTENT_URI, TYPE_INSERT, contactInsert),
+ buildOper(Data.CONTENT_URI, TYPE_INSERT, phoneInsert),
+ buildUpdateAggregationKeepTogether(CONTACT_BOB));
+ }
+
+ public void testMergeUsesNewVersion() {
+ final EntitySet first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
+ buildPhone(PHONE_RED)));
+ final EntitySet second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
+ buildPhone(PHONE_RED)));
+
+ assertEquals((Long)VER_FIRST, getVersion(first, CONTACT_BOB));
+ assertEquals((Long)VER_SECOND, getVersion(second, CONTACT_BOB));
+
+ final EntitySet merged = EntitySet.mergeAfter(second, first);
+ assertEquals((Long)VER_SECOND, getVersion(merged, CONTACT_BOB));
+ }
+
+ public void testMergeAfterEnsureAndTrim() {
+ final EntitySet first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
+ buildEmail(EMAIL_YELLOW)));
+ final EntitySet second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
+ buildEmail(EMAIL_YELLOW)));
+
+ // Ensure we have at least one phone
+ final ContactsSource source = getSource();
+ final EntityDelta bobContact = first.getByRawContactId(CONTACT_BOB);
+ EntityModifier.ensureKindExists(bobContact, source, Phone.CONTENT_ITEM_TYPE);
+ final ValuesDelta bobPhone = bobContact.getSuperPrimaryEntry(Phone.CONTENT_ITEM_TYPE, true);
+
+ // Make sure the update would insert a row
+ assertDiffPattern(first,
+ buildAssertVersion(VER_FIRST),
+ buildUpdateAggregationSuspended(),
+ buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bobPhone, CONTACT_BOB)),
+ buildUpdateAggregationDefault());
+
+ // Trim values and ensure that we don't insert things
+ EntityModifier.trimEmpty(bobContact, source);
+ assertDiffPattern(first);
+
+ // Now re-parent the change, which should remain no-op
+ final EntitySet merged = EntitySet.mergeAfter(second, first);
+ assertDiffPattern(merged);
+ }
+}
diff --git a/tests/src/com/android/contacts/RecentCallsListActivityTests.java b/tests/src/com/android/contacts/RecentCallsListActivityTests.java
new file mode 100644
index 0000000..2cdd8d7
--- /dev/null
+++ b/tests/src/com/android/contacts/RecentCallsListActivityTests.java
@@ -0,0 +1,353 @@
+/*
+ * 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.
+ */
+
+package com.android.contacts;
+
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.provider.CallLog.Calls;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+import android.view.View;
+import android.widget.FrameLayout;
+import com.android.contacts.RecentCallsListActivity;
+import com.android.internal.telephony.CallerInfo;
+import java.util.Date;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.Random;
+
+/**
+ * Tests for the contact call list activity.
+ *
+ * Running all tests:
+ *
+ * runtest contacts
+ * or
+ * adb shell am instrument \
+ * -w com.android.contacts.tests/android.test.InstrumentationTestRunner
+ */
+
+public class RecentCallsListActivityTests
+ extends ActivityInstrumentationTestCase2<RecentCallsListActivity> {
+ static private final String TAG = "RecentCallsListActivityTests";
+ static private final String[] CALL_LOG_PROJECTION = new String[] {
+ Calls._ID,
+ Calls.NUMBER,
+ Calls.DATE,
+ Calls.DURATION,
+ Calls.TYPE,
+ Calls.CACHED_NAME,
+ Calls.CACHED_NUMBER_TYPE,
+ Calls.CACHED_NUMBER_LABEL
+ };
+ static private final int RAND_DURATION = -1;
+ static private final long NOW = -1L;
+
+ // We get the call list activity and assign is a frame to build
+ // its list. mAdapter is an inner class of
+ // RecentCallsListActivity to build the rows (view) in the call
+ // list. We reuse it with our own in-mem DB.
+ private RecentCallsListActivity mActivity;
+ private FrameLayout mParentView;
+ private RecentCallsListActivity.RecentCallsAdapter mAdapter;
+ private String mVoicemail;
+
+ // In memory array to hold the rows corresponding to the 'calls' table.
+ private MatrixCursor mCursor;
+ private int mIndex; // Of the next row.
+
+ private Random mRnd;
+
+ // References to the icons bitmaps used to build the list are stored in a
+ // map mIcons. The keys to retrieve the icons are:
+ // Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE and Calls.MISSED_TYPE.
+ private HashMap<Integer, Bitmap> mCallTypeIcons;
+
+ // An item in the call list. All the methods performing checks use it.
+ private RecentCallsListActivity.RecentCallsListItemViews mItem;
+ // The list of views representing the data in the DB. View are in
+ // reverse order compare to the DB.
+ private View[] mList;
+
+ public RecentCallsListActivityTests() {
+ super("com.android.contacts", RecentCallsListActivity.class);
+ mIndex = 1;
+ mRnd = new Random();
+ }
+
+ @Override
+ public void setUp() {
+ mActivity = (RecentCallsListActivity) getActivity();
+ mVoicemail = mActivity.mVoiceMailNumber;
+ mAdapter = mActivity.mAdapter;
+ mParentView = new FrameLayout(mActivity);
+ mCursor = new MatrixCursor(CALL_LOG_PROJECTION);
+ buildIconMap();
+ }
+
+ /**
+ * Checks that the call icon is not visible for private and
+ * unknown numbers.
+ * Use 2 passes, one where new views are created and one where
+ * half of the total views are updated and the other half created.
+ */
+ @MediumTest
+ public void testCallViewIsNotVisibleForPrivateAndUnknownNumbers() {
+ final int SIZE = 100;
+ mList = new View[SIZE];
+
+ // Insert the first batch of entries.
+ mCursor.moveToFirst();
+ insertRandomEntries(SIZE / 2);
+ int startOfSecondBatch = mCursor.getPosition();
+
+ buildViewListFromDb();
+ checkCallStatus();
+
+ // Append the rest of the entries. We keep the first set of
+ // views around so they get updated and not built from
+ // scratch, this exposes some bugs that are not there when the
+ // call log is launched for the 1st time but show up when the
+ // call log gets updated afterwards.
+ mCursor.move(startOfSecondBatch);
+ insertRandomEntries(SIZE / 2);
+
+ buildViewListFromDb();
+ checkCallStatus();
+ }
+
+ //
+ // HELPERS to check conditions on the DB/views
+ //
+ /**
+ * Check the date of the current list item.
+ * @param date That should be present in the call log list
+ * item. Only NOW is supported.
+ */
+ private void checkDate(long date) {
+ if (NOW == date) {
+ assertEquals("0 mins ago", mItem.dateView.getText());
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Checks the right icon is used to represent the call type
+ * (missed, incoming, outgoing.) in the current item.
+ */
+ private void checkCallType(int type) {
+ Bitmap icon = ((BitmapDrawable) mItem.iconView.getDrawable()).getBitmap();
+ assertEquals(mCallTypeIcons.get(type), icon);
+ }
+
+ /**
+ * Go over all the views in the list and check that the Call
+ * icon's visibility matches the nature of the number.
+ */
+ private void checkCallStatus() {
+ for (int i = 0; i < mList.length; i++) {
+ if (null == mList[i]) {
+ break;
+ }
+ mItem = (RecentCallsListActivity.RecentCallsListItemViews) mList[i].getTag();
+
+ // callView tag is the phone number.
+ String number = (String) mItem.callView.getTag();
+
+ if (CallerInfo.PRIVATE_NUMBER.equals(number) ||
+ CallerInfo.UNKNOWN_NUMBER.equals(number)) {
+ assertFalse(View.VISIBLE == mItem.callView.getVisibility());
+ } else {
+ assertEquals(View.VISIBLE, mItem.callView.getVisibility());
+ }
+ }
+ }
+
+
+ //
+ // HELPERS to setup the tests.
+ //
+
+ /**
+ * Get the Bitmap from the icons in the contacts package.
+ */
+ private Bitmap getBitmap(String resName) {
+ Resources r = mActivity.getResources();
+ int resid = r.getIdentifier(resName, "drawable", "com.android.contacts");
+ BitmapDrawable d = (BitmapDrawable) r.getDrawable(resid);
+ assertNotNull(d);
+ return d.getBitmap();
+ }
+
+ /**
+ * Fetch all the icons we need in tests from the contacts app and store them in a map.
+ */
+ private void buildIconMap() {
+ mCallTypeIcons = new HashMap<Integer, Bitmap>(3);
+
+ mCallTypeIcons.put(Calls.INCOMING_TYPE, getBitmap("ic_call_log_list_incoming_call"));
+ mCallTypeIcons.put(Calls.MISSED_TYPE, getBitmap("ic_call_log_list_missed_call"));
+ mCallTypeIcons.put(Calls.OUTGOING_TYPE, getBitmap("ic_call_log_list_outgoing_call"));
+ }
+
+ //
+ // HELPERS to build/update the call entries (views) from the DB.
+ //
+
+ /**
+ * Read the DB and foreach call either update the existing view if
+ * one exists already otherwise create one.
+ * The list is build from a DESC view of the DB (last inserted entry is first).
+ */
+ private void buildViewListFromDb() {
+ int i = 0;
+ mCursor.moveToLast();
+ while(!mCursor.isBeforeFirst()) {
+ if (null == mList[i]) {
+ mList[i] = mAdapter.newView(mActivity, mCursor, mParentView);
+ }
+ mAdapter.bindView(mList[i], mActivity, mCursor);
+ mCursor.moveToPrevious();
+ i++;
+ }
+ }
+
+ //
+ // HELPERS to insert numbers in the call log DB.
+ //
+
+ /**
+ * Insert a certain number of random numbers in the DB. Makes sure
+ * there is at least one private and one unknown number in the DB.
+ * @param num Of entries to be inserted.
+ */
+ private void insertRandomEntries(int num) {
+ if (num < 10) {
+ throw new IllegalArgumentException("num should be >= 10");
+ }
+ boolean privateOrUnknownOrVm[];
+ privateOrUnknownOrVm = insertRandomRange(0, num - 2);
+
+ if (privateOrUnknownOrVm[0] && privateOrUnknownOrVm[1]) {
+ insertRandomRange(num - 2, num);
+ } else {
+ insertPrivate(NOW, RAND_DURATION);
+ insertUnknown(NOW, RAND_DURATION);
+ }
+ }
+
+ /**
+ * Insert a new call entry in the test DB.
+ * @param number The phone number. For unknown and private numbers,
+ * use CallerInfo.UNKNOWN_NUMBER or CallerInfo.PRIVATE_NUMBER.
+ * @param date In millisec since epoch. Use NOW to use the current time.
+ * @param duration In seconds of the call. Use RAND_DURATION to pick a random one.
+ * @param type Eigher Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE.
+ */
+ private void insert(String number, long date, int duration, int type) {
+ MatrixCursor.RowBuilder row = mCursor.newRow();
+ row.add(mIndex);
+ mIndex ++;
+ row.add(number);
+ if (NOW == date) {
+ row.add(new Date().getTime());
+ }
+ if (duration < 0) {
+ duration = mRnd.nextInt(10 * 60); // 0 - 10 minutes random.
+ }
+ row.add(duration); // duration
+ if (mVoicemail.equals(number)) {
+ assertEquals(Calls.OUTGOING_TYPE, type);
+ }
+ row.add(type); // type
+ row.add(""); // cached name
+ row.add(0); // cached number type
+ row.add(""); // cached number label
+ }
+
+ /**
+ * Insert a new private call entry in the test DB.
+ * @param date In millisec since epoch. Use NOW to use the current time.
+ * @param duration In seconds of the call. Use RAND_DURATION to pick a random one.
+ */
+ private void insertPrivate(long date, int duration) {
+ insert(CallerInfo.PRIVATE_NUMBER, date, duration, Calls.INCOMING_TYPE);
+ }
+
+ /**
+ * Insert a new unknown call entry in the test DB.
+ * @param date In millisec since epoch. Use NOW to use the current time.
+ * @param duration In seconds of the call. Use RAND_DURATION to pick a random one.
+ */
+ private void insertUnknown(long date, int duration) {
+ insert(CallerInfo.UNKNOWN_NUMBER, date, duration, Calls.INCOMING_TYPE);
+ }
+
+ /**
+ * Insert a new voicemail call entry in the test DB.
+ * @param date In millisec since epoch. Use NOW to use the current time.
+ * @param duration In seconds of the call. Use RAND_DURATION to pick a random one.
+ */
+ private void insertVoicemail(long date, int duration) {
+ insert(mVoicemail, date, duration, Calls.OUTGOING_TYPE);
+ }
+
+ /**
+ * Insert a range [start, end) of random numbers in the DB. For
+ * each row, there is a 1/10 probability that the number will be
+ * marked as PRIVATE or UNKNOWN or VOICEMAIL. For regular numbers, a number is
+ * inserted, its last 4 digits will be the number of the iteration
+ * in the range.
+ * @param start Of the range.
+ * @param end Of the range (excluded).
+ * @return An array with 2 booleans [0 = private number, 1 =
+ * unknown number, 2 = voicemail] to indicate if at least one
+ * private or unknown or voicemail number has been inserted. Since
+ * the numbers are random some tests may want to enforce the
+ * insertion of such numbers.
+ */
+ // TODO: Should insert numbers with contact entries too.
+ private boolean[] insertRandomRange(int start, int end) {
+ boolean[] privateOrUnknownOrVm = new boolean[] {false, false, false};
+
+ for (int i = start; i < end; i++ ) {
+ int type = mRnd.nextInt(10);
+
+ if (0 == type) {
+ insertPrivate(NOW, RAND_DURATION);
+ privateOrUnknownOrVm[0] = true;
+ } else if (1 == type) {
+ insertUnknown(NOW, RAND_DURATION);
+ privateOrUnknownOrVm[1] = true;
+ } else if (2 == type) {
+ insertVoicemail(NOW, RAND_DURATION);
+ privateOrUnknownOrVm[2] = true;
+ } else {
+ int inout = mRnd.nextBoolean() ? Calls.OUTGOING_TYPE : Calls.INCOMING_TYPE;
+ String number = new Formatter().format("1800123%04d", i).toString();
+ insert(number, NOW, RAND_DURATION, inout);
+ }
+ }
+ return privateOrUnknownOrVm;
+ }
+}