DO NOT MERGE Bump AOSP Contacts version to 1.5.15
am: f95c1ac573 -s ours
Change-Id: I4d2561b92e45b1eec29c5b86b3395d26fcf3c764
diff --git a/Android.mk b/Android.mk
index 9e9a55a..b19df65 100644
--- a/Android.mk
+++ b/Android.mk
@@ -3,7 +3,6 @@
LOCAL_MODULE_TAGS := optional
-contacts_common_dir := ../ContactsCommon
phone_common_dir := ../PhoneCommon
ifeq ($(TARGET_BUILD_APPS),)
@@ -12,9 +11,9 @@
support_library_root_dir := prebuilts/sdk/current/support
endif
-src_dirs := src $(contacts_common_dir)/src $(phone_common_dir)/src
-res_dirs := res res-aosp $(contacts_common_dir)/res $(contacts_common_dir)/icons/res $(phone_common_dir)/res
-asset_dirs := $(contacts_common_dir)/assets
+src_dirs := src src-bind $(phone_common_dir)/src
+res_dirs := res res-aosp res-icons $(phone_common_dir)/res
+asset_dirs := assets
LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs)) \
@@ -82,5 +81,5 @@
#########################################################################################
-# Use the folloing include to make our test apk.
+# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9995ef1..0bedf6b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,8 +16,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.contacts"
- android:versionCode="10515"
- android:versionName="1.5.15">
+ android:versionCode="10512"
+ android:versionName="1.5.12">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="25" />
diff --git a/assets/licenses.html b/assets/licenses.html
new file mode 100644
index 0000000..c24ed63
--- /dev/null
+++ b/assets/licenses.html
@@ -0,0 +1,247 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta name="viewport" content="width=device-width">
+ <style> body { font-family: sans-serif; } pre { background-color: #eeeeee; padding: 1em; white-space: pre-wrap; word-wrap: break-word; } </style>
+</head>
+<body>
+
+<h3>Notices for: guava, libphonenumber, and libprotobuf-java-nano</h3>
+<pre>
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
+</pre>
+
+<h3>Notices for JSR305</h3>
+<pre>
+Copyright (c) 2007-2009, JSR305 expert group
+All rights reserved.
+
+http://www.opensource.org/licenses/bsd-license.php
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the JSR305 expert group nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+</pre>
+
+</body>
+</html>
diff --git a/proguard.flags b/proguard.flags
index baff4b6..ec75101 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -13,7 +13,7 @@
-keep class com.android.contacts.common.** { *;}
# For test:
--keep class com.android.contacts.commonbind.analytics.AnalyticsUtil { *;}
+-keep class com.android.contactsbind.analytics.AnalyticsUtil { *;}
-keep class com.android.contacts.interactions.** { *;}
-keep class com.google.common.base.Objects { *;}
-keep class com.google.common.base.Preconditions { *;}
diff --git a/res-icons/mipmap-hdpi/ic_contacts_launcher.png b/res-icons/mipmap-hdpi/ic_contacts_launcher.png
new file mode 100644
index 0000000..86380d1
--- /dev/null
+++ b/res-icons/mipmap-hdpi/ic_contacts_launcher.png
Binary files differ
diff --git a/res-icons/mipmap-hdpi/ic_contacts_launcher_square.png b/res-icons/mipmap-hdpi/ic_contacts_launcher_square.png
new file mode 100644
index 0000000..64eff00
--- /dev/null
+++ b/res-icons/mipmap-hdpi/ic_contacts_launcher_square.png
Binary files differ
diff --git a/res-icons/mipmap-mdpi/ic_contacts_launcher.png b/res-icons/mipmap-mdpi/ic_contacts_launcher.png
new file mode 100644
index 0000000..85132c5
--- /dev/null
+++ b/res-icons/mipmap-mdpi/ic_contacts_launcher.png
Binary files differ
diff --git a/res-icons/mipmap-mdpi/ic_contacts_launcher_square.png b/res-icons/mipmap-mdpi/ic_contacts_launcher_square.png
new file mode 100644
index 0000000..b4ee821
--- /dev/null
+++ b/res-icons/mipmap-mdpi/ic_contacts_launcher_square.png
Binary files differ
diff --git a/res-icons/mipmap-xhdpi/ic_contacts_launcher.png b/res-icons/mipmap-xhdpi/ic_contacts_launcher.png
new file mode 100644
index 0000000..c198749
--- /dev/null
+++ b/res-icons/mipmap-xhdpi/ic_contacts_launcher.png
Binary files differ
diff --git a/res-icons/mipmap-xhdpi/ic_contacts_launcher_square.png b/res-icons/mipmap-xhdpi/ic_contacts_launcher_square.png
new file mode 100644
index 0000000..6feeadf
--- /dev/null
+++ b/res-icons/mipmap-xhdpi/ic_contacts_launcher_square.png
Binary files differ
diff --git a/res-icons/mipmap-xxhdpi/ic_contacts_launcher.png b/res-icons/mipmap-xxhdpi/ic_contacts_launcher.png
new file mode 100644
index 0000000..4fa10a6
--- /dev/null
+++ b/res-icons/mipmap-xxhdpi/ic_contacts_launcher.png
Binary files differ
diff --git a/res-icons/mipmap-xxhdpi/ic_contacts_launcher_square.png b/res-icons/mipmap-xxhdpi/ic_contacts_launcher_square.png
new file mode 100644
index 0000000..01a3fde
--- /dev/null
+++ b/res-icons/mipmap-xxhdpi/ic_contacts_launcher_square.png
Binary files differ
diff --git a/res-icons/mipmap-xxxhdpi/ic_contacts_launcher.png b/res-icons/mipmap-xxxhdpi/ic_contacts_launcher.png
new file mode 100644
index 0000000..10bda63
--- /dev/null
+++ b/res-icons/mipmap-xxxhdpi/ic_contacts_launcher.png
Binary files differ
diff --git a/res-icons/mipmap-xxxhdpi/ic_contacts_launcher_square.png b/res-icons/mipmap-xxxhdpi/ic_contacts_launcher_square.png
new file mode 100644
index 0000000..328e067
--- /dev/null
+++ b/res-icons/mipmap-xxxhdpi/ic_contacts_launcher_square.png
Binary files differ
diff --git a/res/color/popup_menu_color.xml b/res/color/popup_menu_color.xml
new file mode 100644
index 0000000..15588c2
--- /dev/null
+++ b/res/color/popup_menu_color.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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_enabled="false" android:alpha="0.5" android:color="#ff000000"/>
+ <item android:color="#ff000000"/>
+</selector>
\ No newline at end of file
diff --git a/res/color/tab_text_color.xml b/res/color/tab_text_color.xml
new file mode 100644
index 0000000..5ef1fe3
--- /dev/null
+++ b/res/color/tab_text_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2014 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:color="@color/actionbar_text_color" android:state_selected="true"/>
+ <item android:color="@color/actionbar_unselected_text_color" />
+</selector>
\ No newline at end of file
diff --git a/res/drawable-hdpi/ic_ab_search.png b/res/drawable-hdpi/ic_ab_search.png
new file mode 100644
index 0000000..d86b219
--- /dev/null
+++ b/res/drawable-hdpi/ic_ab_search.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_add_to_circles_black_24.png b/res/drawable-hdpi/ic_add_to_circles_black_24.png
deleted file mode 100644
index 6eb1fcc..0000000
--- a/res/drawable-hdpi/ic_add_to_circles_black_24.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_arrow_back_24dp.png b/res/drawable-hdpi/ic_arrow_back_24dp.png
new file mode 100644
index 0000000..ddbb2c4
--- /dev/null
+++ b/res/drawable-hdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_business_white_120dp.png b/res/drawable-hdpi/ic_business_white_120dp.png
new file mode 100644
index 0000000..d5942dc
--- /dev/null
+++ b/res/drawable-hdpi/ic_business_white_120dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_24dp.png b/res/drawable-hdpi/ic_call_24dp.png
new file mode 100644
index 0000000..4dc5065
--- /dev/null
+++ b/res/drawable-hdpi/ic_call_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_note_white_24dp.png b/res/drawable-hdpi/ic_call_note_white_24dp.png
new file mode 100644
index 0000000..503e58e
--- /dev/null
+++ b/res/drawable-hdpi/ic_call_note_white_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_call_voicemail_holo_dark.png b/res/drawable-hdpi/ic_call_voicemail_holo_dark.png
new file mode 100644
index 0000000..6d64a36
--- /dev/null
+++ b/res/drawable-hdpi/ic_call_voicemail_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_close_dk.png b/res/drawable-hdpi/ic_close_dk.png
new file mode 100644
index 0000000..9695529
--- /dev/null
+++ b/res/drawable-hdpi/ic_close_dk.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_create_24dp.png b/res/drawable-hdpi/ic_create_24dp.png
new file mode 100644
index 0000000..540ab4d
--- /dev/null
+++ b/res/drawable-hdpi/ic_create_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_group_white_24dp.png b/res/drawable-hdpi/ic_group_white_24dp.png
new file mode 100644
index 0000000..017e4bb
--- /dev/null
+++ b/res/drawable-hdpi/ic_group_white_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_history_white_drawable_24dp.png b/res/drawable-hdpi/ic_history_white_drawable_24dp.png
new file mode 100644
index 0000000..703d30b
--- /dev/null
+++ b/res/drawable-hdpi/ic_history_white_drawable_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_info_outline_24dp.png b/res/drawable-hdpi/ic_info_outline_24dp.png
new file mode 100644
index 0000000..c7b1113
--- /dev/null
+++ b/res/drawable-hdpi/ic_info_outline_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_remove_field_holo_light.png b/res/drawable-hdpi/ic_menu_remove_field_holo_light.png
new file mode 100644
index 0000000..03fd2fb
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_remove_field_holo_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_message_24dp.png b/res/drawable-hdpi/ic_message_24dp.png
new file mode 100644
index 0000000..57177b7
--- /dev/null
+++ b/res/drawable-hdpi/ic_message_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_person_24dp.png b/res/drawable-hdpi/ic_person_24dp.png
new file mode 100644
index 0000000..56708b0
--- /dev/null
+++ b/res/drawable-hdpi/ic_person_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_person_add_24dp.png b/res/drawable-hdpi/ic_person_add_24dp.png
new file mode 100644
index 0000000..10ae5a7
--- /dev/null
+++ b/res/drawable-hdpi/ic_person_add_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_person_avatar.png b/res/drawable-hdpi/ic_person_avatar.png
new file mode 100644
index 0000000..2da477e
--- /dev/null
+++ b/res/drawable-hdpi/ic_person_avatar.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_person_white_120dp.png b/res/drawable-hdpi/ic_person_white_120dp.png
new file mode 100644
index 0000000..69e6f98
--- /dev/null
+++ b/res/drawable-hdpi/ic_person_white_120dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_scroll_handle.png b/res/drawable-hdpi/ic_scroll_handle.png
new file mode 100644
index 0000000..3aa29b8
--- /dev/null
+++ b/res/drawable-hdpi/ic_scroll_handle.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_videocam.png b/res/drawable-hdpi/ic_videocam.png
new file mode 100644
index 0000000..97905c9
--- /dev/null
+++ b/res/drawable-hdpi/ic_videocam.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_voicemail_avatar.png b/res/drawable-hdpi/ic_voicemail_avatar.png
new file mode 100644
index 0000000..2fb7826
--- /dev/null
+++ b/res/drawable-hdpi/ic_voicemail_avatar.png
Binary files differ
diff --git a/res/drawable-hdpi/list_activated_holo.9.png b/res/drawable-hdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..4ea7afa
--- /dev/null
+++ b/res/drawable-hdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_background_holo.9.png b/res/drawable-hdpi/list_background_holo.9.png
new file mode 100644
index 0000000..cddf9be
--- /dev/null
+++ b/res/drawable-hdpi/list_background_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_focused_holo.9.png b/res/drawable-hdpi/list_focused_holo.9.png
new file mode 100644
index 0000000..86578be
--- /dev/null
+++ b/res/drawable-hdpi/list_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_longpressed_holo_light.9.png b/res/drawable-hdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..e9afcc9
--- /dev/null
+++ b/res/drawable-hdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_pressed_holo_light.9.png b/res/drawable-hdpi/list_pressed_holo_light.9.png
new file mode 100644
index 0000000..2054530
--- /dev/null
+++ b/res/drawable-hdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-hdpi/list_title_holo.9.png b/res/drawable-hdpi/list_title_holo.9.png
new file mode 100644
index 0000000..ae93717
--- /dev/null
+++ b/res/drawable-hdpi/list_title_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/unknown_source.png b/res/drawable-hdpi/unknown_source.png
new file mode 100644
index 0000000..0a8f37d
--- /dev/null
+++ b/res/drawable-hdpi/unknown_source.png
Binary files differ
diff --git a/res/drawable-ldrtl-hdpi/list_background_holo.9.png b/res/drawable-ldrtl-hdpi/list_background_holo.9.png
new file mode 100644
index 0000000..0d80482
--- /dev/null
+++ b/res/drawable-ldrtl-hdpi/list_background_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-hdpi/list_focused_holo.9.png b/res/drawable-ldrtl-hdpi/list_focused_holo.9.png
new file mode 100644
index 0000000..4139942
--- /dev/null
+++ b/res/drawable-ldrtl-hdpi/list_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-hdpi/list_title_holo.9.png b/res/drawable-ldrtl-hdpi/list_title_holo.9.png
new file mode 100644
index 0000000..5ec4c96
--- /dev/null
+++ b/res/drawable-ldrtl-hdpi/list_title_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-mdpi/list_background_holo.9.png b/res/drawable-ldrtl-mdpi/list_background_holo.9.png
new file mode 100644
index 0000000..d86d611
--- /dev/null
+++ b/res/drawable-ldrtl-mdpi/list_background_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-mdpi/list_focused_holo.9.png b/res/drawable-ldrtl-mdpi/list_focused_holo.9.png
new file mode 100644
index 0000000..4139942
--- /dev/null
+++ b/res/drawable-ldrtl-mdpi/list_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-mdpi/list_title_holo.9.png b/res/drawable-ldrtl-mdpi/list_title_holo.9.png
new file mode 100644
index 0000000..013d5e7
--- /dev/null
+++ b/res/drawable-ldrtl-mdpi/list_title_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-sw600dp-hdpi/list_activated_holo.9.png b/res/drawable-ldrtl-sw600dp-hdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..947f03c
--- /dev/null
+++ b/res/drawable-ldrtl-sw600dp-hdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-sw600dp-mdpi/list_activated_holo.9.png b/res/drawable-ldrtl-sw600dp-mdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..6d09d72
--- /dev/null
+++ b/res/drawable-ldrtl-sw600dp-mdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-sw600dp-xhdpi/list_activated_holo.9.png b/res/drawable-ldrtl-sw600dp-xhdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..63c7456
--- /dev/null
+++ b/res/drawable-ldrtl-sw600dp-xhdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-xhdpi/list_background_holo.9.png b/res/drawable-ldrtl-xhdpi/list_background_holo.9.png
new file mode 100644
index 0000000..f709f2c
--- /dev/null
+++ b/res/drawable-ldrtl-xhdpi/list_background_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-xhdpi/list_focused_holo.9.png b/res/drawable-ldrtl-xhdpi/list_focused_holo.9.png
new file mode 100644
index 0000000..4139942
--- /dev/null
+++ b/res/drawable-ldrtl-xhdpi/list_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-ldrtl-xhdpi/list_title_holo.9.png b/res/drawable-ldrtl-xhdpi/list_title_holo.9.png
new file mode 100644
index 0000000..cb801ac
--- /dev/null
+++ b/res/drawable-ldrtl-xhdpi/list_title_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_ab_search.png b/res/drawable-mdpi/ic_ab_search.png
new file mode 100644
index 0000000..2b23b1e
--- /dev/null
+++ b/res/drawable-mdpi/ic_ab_search.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_add_to_circles_black_24.png b/res/drawable-mdpi/ic_add_to_circles_black_24.png
deleted file mode 100644
index fbffc97..0000000
--- a/res/drawable-mdpi/ic_add_to_circles_black_24.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_arrow_back_24dp.png b/res/drawable-mdpi/ic_arrow_back_24dp.png
new file mode 100644
index 0000000..1a21fb4
--- /dev/null
+++ b/res/drawable-mdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_business_white_120dp.png b/res/drawable-mdpi/ic_business_white_120dp.png
new file mode 100644
index 0000000..3dddca5
--- /dev/null
+++ b/res/drawable-mdpi/ic_business_white_120dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_24dp.png b/res/drawable-mdpi/ic_call_24dp.png
new file mode 100644
index 0000000..77f9de5
--- /dev/null
+++ b/res/drawable-mdpi/ic_call_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_note_white_24dp.png b/res/drawable-mdpi/ic_call_note_white_24dp.png
new file mode 100644
index 0000000..9d359db
--- /dev/null
+++ b/res/drawable-mdpi/ic_call_note_white_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_call_voicemail_holo_dark.png b/res/drawable-mdpi/ic_call_voicemail_holo_dark.png
new file mode 100644
index 0000000..bf6d006
--- /dev/null
+++ b/res/drawable-mdpi/ic_call_voicemail_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_close_dk.png b/res/drawable-mdpi/ic_close_dk.png
new file mode 100644
index 0000000..590a728
--- /dev/null
+++ b/res/drawable-mdpi/ic_close_dk.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_create_24dp.png b/res/drawable-mdpi/ic_create_24dp.png
new file mode 100644
index 0000000..8a2df39
--- /dev/null
+++ b/res/drawable-mdpi/ic_create_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_group_white_24dp.png b/res/drawable-mdpi/ic_group_white_24dp.png
new file mode 100644
index 0000000..ad268bf
--- /dev/null
+++ b/res/drawable-mdpi/ic_group_white_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_history_white_drawable_24dp.png b/res/drawable-mdpi/ic_history_white_drawable_24dp.png
new file mode 100644
index 0000000..b3000d3
--- /dev/null
+++ b/res/drawable-mdpi/ic_history_white_drawable_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_info_outline_24dp.png b/res/drawable-mdpi/ic_info_outline_24dp.png
new file mode 100644
index 0000000..353e064
--- /dev/null
+++ b/res/drawable-mdpi/ic_info_outline_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_remove_field_holo_light.png b/res/drawable-mdpi/ic_menu_remove_field_holo_light.png
new file mode 100644
index 0000000..8c44e70
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_remove_field_holo_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_star_holo_light.png b/res/drawable-mdpi/ic_menu_star_holo_light.png
new file mode 100644
index 0000000..8263b27
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_star_holo_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_message_24dp.png b/res/drawable-mdpi/ic_message_24dp.png
new file mode 100644
index 0000000..3072b75
--- /dev/null
+++ b/res/drawable-mdpi/ic_message_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_person_24dp.png b/res/drawable-mdpi/ic_person_24dp.png
new file mode 100644
index 0000000..f0b1c72
--- /dev/null
+++ b/res/drawable-mdpi/ic_person_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_person_add_24dp.png b/res/drawable-mdpi/ic_person_add_24dp.png
new file mode 100644
index 0000000..38e0a28
--- /dev/null
+++ b/res/drawable-mdpi/ic_person_add_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_person_avatar.png b/res/drawable-mdpi/ic_person_avatar.png
new file mode 100644
index 0000000..31a40fb
--- /dev/null
+++ b/res/drawable-mdpi/ic_person_avatar.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_person_white_120dp.png b/res/drawable-mdpi/ic_person_white_120dp.png
new file mode 100644
index 0000000..397d933
--- /dev/null
+++ b/res/drawable-mdpi/ic_person_white_120dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_scroll_handle.png b/res/drawable-mdpi/ic_scroll_handle.png
new file mode 100644
index 0000000..af75db4
--- /dev/null
+++ b/res/drawable-mdpi/ic_scroll_handle.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_videocam.png b/res/drawable-mdpi/ic_videocam.png
new file mode 100644
index 0000000..dc9655b
--- /dev/null
+++ b/res/drawable-mdpi/ic_videocam.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_voicemail_avatar.png b/res/drawable-mdpi/ic_voicemail_avatar.png
new file mode 100644
index 0000000..4005f24
--- /dev/null
+++ b/res/drawable-mdpi/ic_voicemail_avatar.png
Binary files differ
diff --git a/res/drawable-mdpi/list_activated_holo.9.png b/res/drawable-mdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..3bf8e03
--- /dev/null
+++ b/res/drawable-mdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_background_holo.9.png b/res/drawable-mdpi/list_background_holo.9.png
new file mode 100644
index 0000000..7d5d66d
--- /dev/null
+++ b/res/drawable-mdpi/list_background_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_focused_holo.9.png b/res/drawable-mdpi/list_focused_holo.9.png
new file mode 100644
index 0000000..86578be
--- /dev/null
+++ b/res/drawable-mdpi/list_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_longpressed_holo_light.9.png b/res/drawable-mdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..3226ab7
--- /dev/null
+++ b/res/drawable-mdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_pressed_holo_light.9.png b/res/drawable-mdpi/list_pressed_holo_light.9.png
new file mode 100644
index 0000000..061904c
--- /dev/null
+++ b/res/drawable-mdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_title_holo.9.png b/res/drawable-mdpi/list_title_holo.9.png
new file mode 100644
index 0000000..64bd691
--- /dev/null
+++ b/res/drawable-mdpi/list_title_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/unknown_source.png b/res/drawable-mdpi/unknown_source.png
new file mode 100644
index 0000000..356748f
--- /dev/null
+++ b/res/drawable-mdpi/unknown_source.png
Binary files differ
diff --git a/res/drawable-sw600dp-hdpi/list_activated_holo.9.png b/res/drawable-sw600dp-hdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..046b24a
--- /dev/null
+++ b/res/drawable-sw600dp-hdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-sw600dp-mdpi/list_activated_holo.9.png b/res/drawable-sw600dp-mdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..1ff3373
--- /dev/null
+++ b/res/drawable-sw600dp-mdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-sw600dp-xhdpi/list_activated_holo.9.png b/res/drawable-sw600dp-xhdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..2eb7c7e
--- /dev/null
+++ b/res/drawable-sw600dp-xhdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-v21/view_pager_tab_background.xml b/res/drawable-v21/view_pager_tab_background.xml
index 00c6db7..b9e0805 100644
--- a/res/drawable-v21/view_pager_tab_background.xml
+++ b/res/drawable-v21/view_pager_tab_background.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2015 The Android Open Source Project
+ ~ Copyright (C) 2016 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,8 +15,8 @@
~ limitations under the License
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/tab_ripple_color">
+ android:color="@color/tab_ripple_color">
<item android:id="@android:id/mask">
<color android:color="@android:color/white" />
</item>
-</ripple>
\ No newline at end of file
+</ripple>
diff --git a/res/drawable-xhdpi/ic_ab_search.png b/res/drawable-xhdpi/ic_ab_search.png
new file mode 100644
index 0000000..71f7827
--- /dev/null
+++ b/res/drawable-xhdpi/ic_ab_search.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_add_to_circles_black_24.png b/res/drawable-xhdpi/ic_add_to_circles_black_24.png
deleted file mode 100644
index 79116b5..0000000
--- a/res/drawable-xhdpi/ic_add_to_circles_black_24.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_arrow_back_24dp.png b/res/drawable-xhdpi/ic_arrow_back_24dp.png
new file mode 100644
index 0000000..bb73272
--- /dev/null
+++ b/res/drawable-xhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_business_white_120dp.png b/res/drawable-xhdpi/ic_business_white_120dp.png
new file mode 100644
index 0000000..6256300
--- /dev/null
+++ b/res/drawable-xhdpi/ic_business_white_120dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_call_24dp.png b/res/drawable-xhdpi/ic_call_24dp.png
new file mode 100644
index 0000000..ef45e93
--- /dev/null
+++ b/res/drawable-xhdpi/ic_call_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_call_note_white_24dp.png b/res/drawable-xhdpi/ic_call_note_white_24dp.png
new file mode 100644
index 0000000..40eed1d
--- /dev/null
+++ b/res/drawable-xhdpi/ic_call_note_white_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_call_voicemail_holo_dark.png b/res/drawable-xhdpi/ic_call_voicemail_holo_dark.png
new file mode 100644
index 0000000..d9684d1
--- /dev/null
+++ b/res/drawable-xhdpi/ic_call_voicemail_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_close_dk.png b/res/drawable-xhdpi/ic_close_dk.png
new file mode 100644
index 0000000..5769f11
--- /dev/null
+++ b/res/drawable-xhdpi/ic_close_dk.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_create_24dp.png b/res/drawable-xhdpi/ic_create_24dp.png
new file mode 100644
index 0000000..48e75be
--- /dev/null
+++ b/res/drawable-xhdpi/ic_create_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_group_white_24dp.png b/res/drawable-xhdpi/ic_group_white_24dp.png
new file mode 100644
index 0000000..09c0e3e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_group_white_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_history_white_drawable_24dp.png b/res/drawable-xhdpi/ic_history_white_drawable_24dp.png
new file mode 100644
index 0000000..e188d4a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_history_white_drawable_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_info_outline_24dp.png b/res/drawable-xhdpi/ic_info_outline_24dp.png
new file mode 100644
index 0000000..c571b2e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_info_outline_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_remove_field_holo_light.png b/res/drawable-xhdpi/ic_menu_remove_field_holo_light.png
new file mode 100644
index 0000000..65a6b7b
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_remove_field_holo_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_message_24dp.png b/res/drawable-xhdpi/ic_message_24dp.png
new file mode 100644
index 0000000..763767b
--- /dev/null
+++ b/res/drawable-xhdpi/ic_message_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_person_24dp.png b/res/drawable-xhdpi/ic_person_24dp.png
new file mode 100644
index 0000000..aea15f0
--- /dev/null
+++ b/res/drawable-xhdpi/ic_person_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_person_add_24dp.png b/res/drawable-xhdpi/ic_person_add_24dp.png
new file mode 100644
index 0000000..7e7c289
--- /dev/null
+++ b/res/drawable-xhdpi/ic_person_add_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_person_avatar.png b/res/drawable-xhdpi/ic_person_avatar.png
new file mode 100644
index 0000000..aecc9af
--- /dev/null
+++ b/res/drawable-xhdpi/ic_person_avatar.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_person_white_120dp.png b/res/drawable-xhdpi/ic_person_white_120dp.png
new file mode 100644
index 0000000..8d80a05
--- /dev/null
+++ b/res/drawable-xhdpi/ic_person_white_120dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_scroll_handle.png b/res/drawable-xhdpi/ic_scroll_handle.png
new file mode 100644
index 0000000..2d43c4d
--- /dev/null
+++ b/res/drawable-xhdpi/ic_scroll_handle.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_videocam.png b/res/drawable-xhdpi/ic_videocam.png
new file mode 100644
index 0000000..c1783de
--- /dev/null
+++ b/res/drawable-xhdpi/ic_videocam.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_voicemail_avatar.png b/res/drawable-xhdpi/ic_voicemail_avatar.png
new file mode 100644
index 0000000..f24505d
--- /dev/null
+++ b/res/drawable-xhdpi/ic_voicemail_avatar.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_activated_holo.9.png b/res/drawable-xhdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..eda10e6
--- /dev/null
+++ b/res/drawable-xhdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_background_holo.9.png b/res/drawable-xhdpi/list_background_holo.9.png
new file mode 100644
index 0000000..b652725
--- /dev/null
+++ b/res/drawable-xhdpi/list_background_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_focused_holo.9.png b/res/drawable-xhdpi/list_focused_holo.9.png
new file mode 100644
index 0000000..86578be
--- /dev/null
+++ b/res/drawable-xhdpi/list_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_longpressed_holo_light.9.png b/res/drawable-xhdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..5532e88
--- /dev/null
+++ b/res/drawable-xhdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_pressed_holo_light.9.png b/res/drawable-xhdpi/list_pressed_holo_light.9.png
new file mode 100644
index 0000000..f4af926
--- /dev/null
+++ b/res/drawable-xhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_title_holo.9.png b/res/drawable-xhdpi/list_title_holo.9.png
new file mode 100644
index 0000000..f4f00ca
--- /dev/null
+++ b/res/drawable-xhdpi/list_title_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/unknown_source.png b/res/drawable-xhdpi/unknown_source.png
new file mode 100644
index 0000000..35e8fb4
--- /dev/null
+++ b/res/drawable-xhdpi/unknown_source.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_ab_search.png b/res/drawable-xxhdpi/ic_ab_search.png
new file mode 100644
index 0000000..142c545
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_ab_search.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_add_to_circles_black_24.png b/res/drawable-xxhdpi/ic_add_to_circles_black_24.png
deleted file mode 100644
index 23a2084..0000000
--- a/res/drawable-xxhdpi/ic_add_to_circles_black_24.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_arrow_back_24dp.png b/res/drawable-xxhdpi/ic_arrow_back_24dp.png
new file mode 100644
index 0000000..72c51b0
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_business_white_120dp.png b/res/drawable-xxhdpi/ic_business_white_120dp.png
new file mode 100644
index 0000000..8d67e44
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_business_white_120dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_call_24dp.png b/res/drawable-xxhdpi/ic_call_24dp.png
new file mode 100644
index 0000000..90ead2e
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_call_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_call_note_white_24dp.png b/res/drawable-xxhdpi/ic_call_note_white_24dp.png
new file mode 100644
index 0000000..2656cad
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_call_note_white_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_call_voicemail_holo_dark.png b/res/drawable-xxhdpi/ic_call_voicemail_holo_dark.png
new file mode 100644
index 0000000..ac5b83b
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_call_voicemail_holo_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_close_dk.png b/res/drawable-xxhdpi/ic_close_dk.png
new file mode 100644
index 0000000..670bf79
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_close_dk.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_create_24dp.png b/res/drawable-xxhdpi/ic_create_24dp.png
new file mode 100644
index 0000000..24142c7
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_create_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_group_white_24dp.png b/res/drawable-xxhdpi/ic_group_white_24dp.png
new file mode 100644
index 0000000..03cad4c
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_group_white_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_history_white_drawable_24dp.png b/res/drawable-xxhdpi/ic_history_white_drawable_24dp.png
new file mode 100644
index 0000000..f44df1a
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_history_white_drawable_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_info_outline_24dp.png b/res/drawable-xxhdpi/ic_info_outline_24dp.png
new file mode 100644
index 0000000..c41a5fc
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_info_outline_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_remove_field_holo_light.png b/res/drawable-xxhdpi/ic_menu_remove_field_holo_light.png
new file mode 100644
index 0000000..0fec2f2
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_remove_field_holo_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_message_24dp.png b/res/drawable-xxhdpi/ic_message_24dp.png
new file mode 100644
index 0000000..0a79824
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_message_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_person_24dp.png b/res/drawable-xxhdpi/ic_person_24dp.png
new file mode 100644
index 0000000..184f741
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_person_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_person_add_24dp.png b/res/drawable-xxhdpi/ic_person_add_24dp.png
new file mode 100644
index 0000000..8f744f0
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_person_add_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_person_avatar.png b/res/drawable-xxhdpi/ic_person_avatar.png
new file mode 100644
index 0000000..2cfc004
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_person_avatar.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_person_white_120dp.png b/res/drawable-xxhdpi/ic_person_white_120dp.png
new file mode 100644
index 0000000..b29df2f
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_person_white_120dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_scroll_handle.png b/res/drawable-xxhdpi/ic_scroll_handle.png
new file mode 100644
index 0000000..55f1d13
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_scroll_handle.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_videocam.png b/res/drawable-xxhdpi/ic_videocam.png
new file mode 100644
index 0000000..4ab5ad0
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_videocam.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_voicemail_avatar.png b/res/drawable-xxhdpi/ic_voicemail_avatar.png
new file mode 100644
index 0000000..182def8
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_voicemail_avatar.png
Binary files differ
diff --git a/res/drawable-xxhdpi/list_activated_holo.9.png b/res/drawable-xxhdpi/list_activated_holo.9.png
new file mode 100644
index 0000000..52c00dd
--- /dev/null
+++ b/res/drawable-xxhdpi/list_activated_holo.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/list_focused_holo.9.png b/res/drawable-xxhdpi/list_focused_holo.9.png
new file mode 100644
index 0000000..3e4ca68
--- /dev/null
+++ b/res/drawable-xxhdpi/list_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/list_longpressed_holo_light.9.png b/res/drawable-xxhdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..230d649
--- /dev/null
+++ b/res/drawable-xxhdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/list_pressed_holo_light.9.png b/res/drawable-xxhdpi/list_pressed_holo_light.9.png
new file mode 100644
index 0000000..1352a17
--- /dev/null
+++ b/res/drawable-xxhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/list_title_holo.9.png b/res/drawable-xxhdpi/list_title_holo.9.png
new file mode 100644
index 0000000..7ddf14a
--- /dev/null
+++ b/res/drawable-xxhdpi/list_title_holo.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_ab_search.png b/res/drawable-xxxhdpi/ic_ab_search.png
new file mode 100644
index 0000000..2ffb2ec
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_ab_search.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_arrow_back_24dp.png b/res/drawable-xxxhdpi/ic_arrow_back_24dp.png
new file mode 100644
index 0000000..ae01a04
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_business_white_120dp.png b/res/drawable-xxxhdpi/ic_business_white_120dp.png
new file mode 100644
index 0000000..1741675
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_business_white_120dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_call_24dp.png b/res/drawable-xxxhdpi/ic_call_24dp.png
new file mode 100644
index 0000000..b0e0205
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_call_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_call_note_white_24dp.png b/res/drawable-xxxhdpi/ic_call_note_white_24dp.png
new file mode 100644
index 0000000..903c162
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_call_note_white_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_close_dk.png b/res/drawable-xxxhdpi/ic_close_dk.png
new file mode 100644
index 0000000..3a5540f
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_close_dk.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_create_24dp.png b/res/drawable-xxxhdpi/ic_create_24dp.png
new file mode 100644
index 0000000..d3ff0ec
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_create_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_history_white_drawable_24dp.png b/res/drawable-xxxhdpi/ic_history_white_drawable_24dp.png
new file mode 100644
index 0000000..5b96af5
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_history_white_drawable_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_info_outline_24dp.png b/res/drawable-xxxhdpi/ic_info_outline_24dp.png
new file mode 100644
index 0000000..3a82cab
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_info_outline_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_message_24dp.png b/res/drawable-xxxhdpi/ic_message_24dp.png
new file mode 100644
index 0000000..fa7c17a
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_message_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_person_24dp.png b/res/drawable-xxxhdpi/ic_person_24dp.png
new file mode 100644
index 0000000..33d40d8
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_person_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_person_add_24dp.png b/res/drawable-xxxhdpi/ic_person_add_24dp.png
new file mode 100644
index 0000000..2fa2cca
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_person_add_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_person_avatar.png b/res/drawable-xxxhdpi/ic_person_avatar.png
new file mode 100644
index 0000000..3233252
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_person_avatar.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_person_white_120dp.png b/res/drawable-xxxhdpi/ic_person_white_120dp.png
new file mode 100644
index 0000000..b53cc11
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_person_white_120dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_scroll_handle.png b/res/drawable-xxxhdpi/ic_scroll_handle.png
new file mode 100644
index 0000000..d90782a
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_scroll_handle.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_videocam.png b/res/drawable-xxxhdpi/ic_videocam.png
new file mode 100644
index 0000000..0643ea5
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_videocam.png
Binary files differ
diff --git a/res/drawable/dialog_background_material.xml b/res/drawable/dialog_background_material.xml
new file mode 100644
index 0000000..fb586a0
--- /dev/null
+++ b/res/drawable/dialog_background_material.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="16dp">
+ <shape android:shape="rectangle">
+ <corners android:radius="2dp" />
+ <solid android:color="@color/call_subject_history_background" />
+ </shape>
+</inset>
diff --git a/res/drawable/fastscroll_thumb.xml b/res/drawable/fastscroll_thumb.xml
new file mode 100644
index 0000000..eca4b39
--- /dev/null
+++ b/res/drawable/fastscroll_thumb.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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/ic_scroll_handle_pressed" />
+ <item android:drawable="@drawable/ic_scroll_handle_default" />
+</selector>
\ No newline at end of file
diff --git a/res/drawable/ic_back_arrow.xml b/res/drawable/ic_back_arrow.xml
new file mode 100644
index 0000000..68a875d
--- /dev/null
+++ b/res/drawable/ic_back_arrow.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2014 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
+ -->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_arrow_back_24dp"
+ android:autoMirrored="true"
+ android:tint="@color/actionbar_icon_color" />
\ No newline at end of file
diff --git a/res/drawable/ic_call.xml b/res/drawable/ic_call.xml
new file mode 100644
index 0000000..e06317b
--- /dev/null
+++ b/res/drawable/ic_call.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_call_24dp"
+ android:autoMirrored="true" />
diff --git a/res/drawable/ic_cancel_black_24dp.xml b/res/drawable/ic_cancel_black_24dp.xml
new file mode 100644
index 0000000..30f8ef5
--- /dev/null
+++ b/res/drawable/ic_cancel_black_24dp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<!-- An 'x' with a circle around it (used as a delete button). -->
+<vector android:alpha="0.54" android:height="24dp"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#000000" android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z"/>
+</vector>
diff --git a/res/drawable/ic_check_mark.xml b/res/drawable/ic_check_mark.xml
new file mode 100644
index 0000000..b0d73cd
--- /dev/null
+++ b/res/drawable/ic_check_mark.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<!-- Checkmark icon used when some task is done -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_close_black_24dp.xml b/res/drawable/ic_close_black_24dp.xml
new file mode 100644
index 0000000..4ddacdf
--- /dev/null
+++ b/res/drawable/ic_close_black_24dp.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<!-- 'X' icon (used in multi select mode and search bar). -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+ <path
+ android:fillColor="#000000"
+ android:pathData="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
+</vector>
diff --git a/res/drawable/ic_device.xml b/res/drawable/ic_device.xml
new file mode 100644
index 0000000..7fd3bd5
--- /dev/null
+++ b/res/drawable/ic_device.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- ic_device is a phone-shaped icon. Since it is not tinted so we set the tint color in here. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+<path
+ android:fillColor="#7f7f7f"
+ android:pathData="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_material_star.xml b/res/drawable/ic_material_star.xml
new file mode 100644
index 0000000..cd7c61c
--- /dev/null
+++ b/res/drawable/ic_material_star.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<!-- Material design star icon -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+<path
+ android:fillColor="#000000"
+ android:pathData="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_message_24dp_mirrored.xml b/res/drawable/ic_message_24dp_mirrored.xml
new file mode 100644
index 0000000..b1bd743
--- /dev/null
+++ b/res/drawable/ic_message_24dp_mirrored.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_message_24dp"
+ android:autoMirrored="true" />
diff --git a/res/drawable/ic_more_vert.xml b/res/drawable/ic_more_vert.xml
new file mode 100644
index 0000000..749316a
--- /dev/null
+++ b/res/drawable/ic_more_vert.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
+</vector>
diff --git a/res/drawable/ic_person_add_tinted_24dp.xml b/res/drawable/ic_person_add_tinted_24dp.xml
new file mode 100644
index 0000000..fdbf4fa
--- /dev/null
+++ b/res/drawable/ic_person_add_tinted_24dp.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2014 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
+ -->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_person_add_24dp"
+ android:autoMirrored="true"/>
diff --git a/res/drawable/ic_scroll_handle_default.xml b/res/drawable/ic_scroll_handle_default.xml
new file mode 100644
index 0000000..055005e
--- /dev/null
+++ b/res/drawable/ic_scroll_handle_default.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_scroll_handle"
+ android:tint="@color/dialtacts_secondary_text_color" />
\ No newline at end of file
diff --git a/res/drawable/ic_scroll_handle_pressed.xml b/res/drawable/ic_scroll_handle_pressed.xml
new file mode 100644
index 0000000..9109c81
--- /dev/null
+++ b/res/drawable/ic_scroll_handle_pressed.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_scroll_handle"
+ android:tint="@color/dialtacts_theme_color" />
\ No newline at end of file
diff --git a/res/drawable/ic_search_add_contact.xml b/res/drawable/ic_search_add_contact.xml
new file mode 100644
index 0000000..9a313cd
--- /dev/null
+++ b/res/drawable/ic_search_add_contact.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_person_add_24dp"
+ android:autoMirrored="true" />
diff --git a/res/drawable/ic_search_video_call.xml b/res/drawable/ic_search_video_call.xml
new file mode 100644
index 0000000..c2390e5
--- /dev/null
+++ b/res/drawable/ic_search_video_call.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/ic_videocam"
+ android:autoMirrored="true"
+ android:tint="@color/search_video_call_icon_tint" />
diff --git a/res/drawable/ic_work_profile.xml b/res/drawable/ic_work_profile.xml
new file mode 100644
index 0000000..bacfe69
--- /dev/null
+++ b/res/drawable/ic_work_profile.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="16dp"
+ android:height="16dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <!-- //java/com/google/android/assets/quantum:ic_enterprise_grey600_16 -->
+
+ <path
+ android:fillColor="#757575"
+ android:pathData="M28 33h-8v-3H6v8c0 2.2 1.8 4 4 4h28c2.2 0 4-1.8
+4-4v-8H28v3zm12-21h-7V9l-3-3H18l-3 3.1V12H8c-2.2 0-4 1.8-4 4v8c0 2.2 1.8 4 4
+4h12v-3h8v3h12c2.2 0 4-1.8 4-4v-8c0-2.2-1.8-4-4-4zm-10 0H18V9h12v3z" />
+ <path
+ android:pathData="M0 0h48v48H0z" />
+</vector>
diff --git a/res/drawable/item_background_material_borderless_dark.xml b/res/drawable/item_background_material_borderless_dark.xml
new file mode 100644
index 0000000..693bcaf
--- /dev/null
+++ b/res/drawable/item_background_material_borderless_dark.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<!-- Based on the Theme.Material's default selectableItemBackgroundBorderless -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/ripple_material_dark" />
\ No newline at end of file
diff --git a/res/drawable/item_background_material_dark.xml b/res/drawable/item_background_material_dark.xml
new file mode 100644
index 0000000..87b1e17
--- /dev/null
+++ b/res/drawable/item_background_material_dark.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<!-- Based on the Theme.Material's default selectableItemBackground -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/ripple_material_dark" >
+ <item android:id="@android:id/mask">
+ <color android:color="@android:color/white" />
+ </item>
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/list_item_activated_background.xml b/res/drawable/list_item_activated_background.xml
new file mode 100644
index 0000000..a58577e
--- /dev/null
+++ b/res/drawable/list_item_activated_background.xml
@@ -0,0 +1,20 @@
+<?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_activated="true" android:drawable="@drawable/list_activated_holo" />
+ <item android:drawable="@drawable/list_background_holo" />
+</selector>
diff --git a/res/drawable/searchedittext_custom_cursor.xml b/res/drawable/searchedittext_custom_cursor.xml
new file mode 100644
index 0000000..a6bb90f
--- /dev/null
+++ b/res/drawable/searchedittext_custom_cursor.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2014 Google Inc. All Rights Reserved. -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size android:width="2dp" android:height="22dp" />
+ <solid android:color="@color/dialtacts_theme_color" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/unread_count_background.xml b/res/drawable/unread_count_background.xml
new file mode 100644
index 0000000..f70f84a
--- /dev/null
+++ b/res/drawable/unread_count_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners android:radius="@dimen/tab_unread_count_background_radius"/>
+ <solid android:color="@color/tab_unread_count_background_color" />
+</shape>
diff --git a/res/drawable/view_pager_tab_background.xml b/res/drawable/view_pager_tab_background.xml
index f1ddbe2..9f59845 100644
--- a/res/drawable/view_pager_tab_background.xml
+++ b/res/drawable/view_pager_tab_background.xml
@@ -17,5 +17,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
- android:drawable="@color/primary_color_dark"/>
+ android:drawable="@color/tab_ripple_color"/>
</selector>
\ No newline at end of file
diff --git a/res/layout-ldrtl/unread_count_tab.xml b/res/layout-ldrtl/unread_count_tab.xml
new file mode 100644
index 0000000..b23ab57
--- /dev/null
+++ b/res/layout-ldrtl/unread_count_tab.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<!-- layoutDirection set to ltr as a workaround to a framework bug (b/22010411) causing view with
+ layout_centerInParent inside a RelativeLayout to expand to screen width when RTL is active -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/view_pager_tab_background"
+ android:layoutDirection="ltr">
+ <!-- The tab icon -->
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"/>
+ <TextView
+ android:id="@+id/count"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/tab_unread_count_background_size"
+ android:layout_marginTop="@dimen/tab_unread_count_margin_top"
+ android:layout_marginStart="@dimen/tab_unread_count_margin_left"
+ android:layout_toStartOf="@id/icon"
+ android:paddingLeft="@dimen/tab_unread_count_text_padding"
+ android:paddingRight="@dimen/tab_unread_count_text_padding"
+ android:background="@drawable/unread_count_background"
+ android:fontFamily="sans-serif-medium"
+ android:importantForAccessibility="no"
+ android:minWidth="@dimen/tab_unread_count_background_size"
+ android:textAlignment="center"
+ android:textColor="@color/tab_accent_color"
+ android:textSize="@dimen/tab_unread_count_text_size"
+ android:layoutDirection="locale"/>
+</RelativeLayout>
+
diff --git a/res/layout/account_filter_header.xml b/res/layout/account_filter_header.xml
new file mode 100644
index 0000000..d348e82
--- /dev/null
+++ b/res/layout/account_filter_header.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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 showing the type of account filter
+ (e.g. All contacts filter, custom filter, etc.),
+ which is the header of all contact lists. -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/account_filter_header_container"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/contact_browser_list_header_height"
+ android:paddingTop="@dimen/list_header_extra_top_padding"
+ android:visibility="gone"
+ android:orientation="horizontal"
+ android:background="@color/background_primary">
+
+ <ImageView
+ android:id="@+id/account_filter_icon"
+ android:layout_height="@dimen/contact_browser_list_header_icon_size"
+ android:layout_width="@dimen/contact_browser_list_header_icon_size"
+ android:layout_marginStart="@dimen/contact_browser_list_header_icon_left_margin"
+ android:layout_marginEnd="@dimen/contact_browser_list_header_icon_right_margin"
+ android:layout_gravity="center_vertical"/>
+
+ <TextView
+ android:id="@+id/account_filter_header"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="@dimen/contact_browser_list_header_text_margin"
+ android:layout_marginEnd="@dimen/contact_browser_list_header_right_margin"
+ style="@style/ContactListSeparatorTextViewStyle"
+ android:textAlignment="viewStart"
+ android:paddingLeft="@dimen/contact_browser_list_item_text_indent"
+ android:paddingStart="@dimen/contact_browser_list_item_text_indent" />
+</LinearLayout>
diff --git a/res/layout/account_selector_list_item.xml b/res/layout/account_selector_list_item.xml
new file mode 100644
index 0000000..ba86a9b
--- /dev/null
+++ b/res/layout/account_selector_list_item.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:orientation="horizontal">
+ <ImageView android:id="@android:id/icon"
+ android:layout_width="@dimen/detail_network_icon_size"
+ android:layout_height="@dimen/detail_network_icon_size"
+ android:layout_margin="16dip"
+ android:layout_gravity="center_vertical" />
+
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="8dp"
+ android:orientation="vertical"
+ android:layout_gravity="center_vertical">
+
+ <TextView android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="8dip"
+ android:layout_marginEnd="8dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:singleLine="true"
+ android:ellipsize="end"/>
+
+ <TextView android:id="@android:id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="8dip"
+ android:layout_marginEnd="8dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:singleLine="true"
+ android:ellipsize="end"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/account_selector_list_item_condensed.xml b/res/layout/account_selector_list_item_condensed.xml
new file mode 100644
index 0000000..6720065
--- /dev/null
+++ b/res/layout/account_selector_list_item_condensed.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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="280dp"
+ android:layout_height="72dp"
+ android:orientation="horizontal">
+ <ImageView android:id="@android:id/icon"
+ android:layout_width="@dimen/detail_network_icon_size"
+ android:layout_height="@dimen/detail_network_icon_size"
+ android:layout_marginStart="24dp"
+ android:layout_marginEnd="16dp"
+ android:layout_gravity="center_vertical" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:layout_gravity="center_vertical">
+
+ <TextView android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="8dip"
+ android:layout_marginEnd="8dip"
+ android:textSize="16sp"
+ android:textColor="@color/contacts_text_color"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:singleLine="true"
+ android:ellipsize="end"/>
+
+ <TextView android:id="@android:id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="8dip"
+ android:layout_marginEnd="8dip"
+ android:textSize="14sp"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:singleLine="true"
+ android:ellipsize="end"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/call_subject_history_list_item.xml b/res/layout/call_subject_history_list_item.xml
new file mode 100644
index 0000000..b8cce47
--- /dev/null
+++ b/res/layout/call_subject_history_list_item.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:gravity="center_vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/call_subject_dialog_margin"
+ android:paddingEnd="@dimen/call_subject_dialog_margin"
+ android:paddingTop="@dimen/call_subject_history_item_padding"
+ android:paddingBottom="@dimen/call_subject_history_item_padding"
+ android:singleLine="true"
+ android:textColor="@color/dialtacts_primary_text_color"
+ android:textSize="@dimen/call_subject_dialog_primary_text_size" />
diff --git a/res/layout/contact_list_card.xml b/res/layout/contact_list_card.xml
new file mode 100644
index 0000000..c20dbe7
--- /dev/null
+++ b/res/layout/contact_list_card.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:id="@+id/list_card"
+ android:visibility="invisible">
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/contact_all_list_background_color"/>
+</LinearLayout>
diff --git a/res/layout/contact_list_content.xml b/res/layout/contact_list_content.xml
new file mode 100644
index 0000000..f18267d
--- /dev/null
+++ b/res/layout/contact_list_content.xml
@@ -0,0 +1,65 @@
+<?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.
+-->
+
+<!-- android:paddingTop is used instead of android:layout_marginTop. It looks
+ android:layout_marginTop is ignored when used with <fragment></fragment>, which
+ only happens in Tablet UI since we rely on ViewPager in Phone UI.
+ Instead, android:layout_marginTop inside <fragment /> is effective. -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pinned_header_list_layout"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ android:background="?attr/contact_browser_background" >
+
+ <!-- Shown only when an Account filter is set.
+ - paddingTop should be here to show "shade" effect correctly. -->
+ <include layout="@layout/account_filter_header" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:id="@+id/contact_list">
+
+ <include layout="@layout/contact_list_card"/>
+ <view
+ class="com.android.contacts.common.list.PinnedHeaderListView"
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="?attr/contact_browser_list_padding_left"
+ android:layout_marginRight="?attr/contact_browser_list_padding_right"
+ android:layout_marginStart="?attr/contact_browser_list_padding_left"
+ android:layout_marginEnd="?attr/contact_browser_list_padding_right"
+ android:paddingTop="?attr/list_item_padding_top"
+ android:clipToPadding="false"
+ android:fastScrollEnabled="true"
+ android:visibility="gone"
+ android:fadingEdge="none" />
+ <ProgressBar
+ android:id="@+id/search_progress"
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="gone" />
+ </FrameLayout>
+
+</LinearLayout>
diff --git a/res/layout/contact_list_filter.xml b/res/layout/contact_list_filter.xml
new file mode 100644
index 0000000..34c713c
--- /dev/null
+++ b/res/layout/contact_list_filter.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2011 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="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:fillViewport="true">
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/dividerHorizontal" />
+</LinearLayout>
diff --git a/res/layout/contact_list_filter_custom.xml b/res/layout/contact_list_filter_custom.xml
new file mode 100644
index 0000000..845d52f
--- /dev/null
+++ b/res/layout/contact_list_filter_custom.xml
@@ -0,0 +1,39 @@
+<?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"
+ style="@style/CustomContactListFilterView"
+ android:orientation="vertical"
+ android:fillViewport="true">
+
+ <ExpandableListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:overScrollMode="always" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:background="?android:attr/dividerHorizontal" />
+
+</LinearLayout>
diff --git a/res/layout/contact_list_filter_item.xml b/res/layout/contact_list_filter_item.xml
new file mode 100644
index 0000000..9f297e6
--- /dev/null
+++ b/res/layout/contact_list_filter_item.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.contacts.common.list.ContactListFilterView"
+ android:descendantFocusability="blocksDescendants"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/contact_filter_left_margin"
+ android:paddingEnd="@dimen/contact_filter_right_margin"
+ android:minHeight="@dimen/contact_filter_item_min_height"
+ android:gravity="center_vertical">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:scaleType="fitCenter"
+ android:layout_width="@dimen/contact_filter_icon_size"
+ android:layout_height="@dimen/contact_filter_icon_size"/>
+
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginTop="-1dip"
+ android:orientation="vertical"
+ android:layout_marginLeft="8dip"
+ android:layout_marginStart="8dip">
+
+ <TextView
+ android:id="@+id/accountType"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:textColor="@color/account_filter_text_color"
+ android:singleLine="true"
+ android:ellipsize="end"/>
+
+ <TextView
+ android:id="@+id/accountUserName"
+ android:layout_marginTop="-3dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:textColor="@color/account_filter_text_color"
+ android:singleLine="true"
+ android:ellipsize="end"/>
+ </LinearLayout>
+
+ <RadioButton
+ android:id="@+id/radioButton"
+ android:clickable="false"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|center_vertical" />
+</view>
+
diff --git a/res/layout/contact_tile_frequent.xml b/res/layout/contact_tile_frequent.xml
new file mode 100644
index 0000000..b1e83ce
--- /dev/null
+++ b/res/layout/contact_tile_frequent.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.contacts.common.list.ContactTileFrequentView"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:paddingTop="?list_item_padding_top"
+ android:paddingBottom="?list_item_padding_bottom">
+
+ <com.android.contacts.common.widget.LayoutSuppressingImageView
+ android:id="@+id/contact_tile_image"
+ android:layout_width="?list_item_photo_size"
+ android:layout_height="?list_item_photo_size"
+ android:scaleType="centerCrop"
+ android:layout_marginEnd="?list_item_gap_between_image_and_text"/>
+
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:textSize="@dimen/contact_browser_list_item_text_size"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee"
+ android:textAlignment="viewStart" />
+
+ </LinearLayout>
+
+</view>
diff --git a/res/layout/contact_tile_frequent_phone.xml b/res/layout/contact_tile_frequent_phone.xml
new file mode 100644
index 0000000..f87dff7
--- /dev/null
+++ b/res/layout/contact_tile_frequent_phone.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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 parameters are set programmatically. -->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/contact_tile_frequent_phone"
+ class="com.android.contacts.common.list.ContactTilePhoneFrequentView"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground"
+ android:nextFocusLeft="@+id/contact_tile_quick">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <com.android.contacts.common.widget.LayoutSuppressingQuickContactBadge
+ android:id="@id/contact_tile_quick"
+ android:layout_width="64dip"
+ android:layout_height="64dip"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:nextFocusRight="@id/contact_tile_frequent_phone"
+ android:scaleType="centerCrop"
+ android:focusable="true" />
+
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ android:layout_marginStart="8dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_marginTop="8dip"
+ android:layout_toRightOf="@id/contact_tile_quick"
+ android:layout_toEndOf="@id/contact_tile_quick"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee"
+ android:textAlignment="viewStart" />
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/contact_tile_name"
+ android:layout_toRightOf="@id/contact_tile_quick"
+ android:layout_toEndOf="@id/contact_tile_quick"
+ android:gravity="center_vertical">
+
+ <TextView
+ android:id="@+id/contact_tile_phone_number"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="?attr/list_item_data_width_weight"
+ android:textSize="14sp"
+ android:ellipsize="marquee"
+ android:textColor="@color/dialtacts_secondary_text_color"
+ android:layout_marginLeft="8dip"
+ android:layout_marginStart="8dip"
+ android:singleLine="true"
+ android:layout_gravity="bottom"
+ android:textDirection="ltr"
+ android:textAlignment="viewStart" />
+
+ <TextView
+ android:id="@+id/contact_tile_phone_type"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="?attr/list_item_label_width_weight"
+ android:textSize="12sp"
+ android:ellipsize="marquee"
+ android:singleLine="true"
+ android:textAllCaps="true"
+ android:textColor="@color/dialtacts_secondary_text_color"
+ android:layout_marginLeft="8dip"
+ android:layout_marginStart="8dip"
+ android:gravity="end"
+ android:layout_gravity="bottom" />
+
+ </LinearLayout>
+
+ <View
+ android:id="@+id/contact_tile_horizontal_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="?android:attr/listDivider"
+ android:layout_below="@id/contact_tile_quick" />
+
+ </RelativeLayout>
+
+</view>
diff --git a/res/layout/contact_tile_starred.xml b/res/layout/contact_tile_starred.xml
new file mode 100644
index 0000000..777cc05
--- /dev/null
+++ b/res/layout/contact_tile_starred.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:ex="http://schemas.android.com/apk/res-auto"
+ class="com.android.contacts.common.list.ContactTileStarredView"
+ android:focusable="true"
+ android:background="?android:attr/selectableItemBackground">
+
+ <LinearLayout
+ android:id="@+id/contact_tile_push_state"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingTop="24dp">
+ <view
+ android:id="@+id/contact_tile_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ ex:direction="widthToHeight"
+ ex:ratio="1.0"
+ class="com.android.contacts.common.widget.ProportionalLayout" >
+ <ImageView
+ android:id="@+id/contact_tile_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ </view>
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="7dp"
+ android:textColor="#202020"
+ android:textSize="@dimen/contact_browser_list_item_text_size"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee"
+ android:textAlignment="center"/>
+ </LinearLayout>
+</view>
diff --git a/res/layout/contact_tile_starred_quick_contact.xml b/res/layout/contact_tile_starred_quick_contact.xml
new file mode 100644
index 0000000..ecbe583
--- /dev/null
+++ b/res/layout/contact_tile_starred_quick_contact.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingBottom="1dip"
+ android:paddingRight="1dip"
+ android:paddingEnd="1dip"
+ android:background="@null"
+ class="com.android.contacts.common.list.ContactTileStarredView" >
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <com.android.contacts.common.widget.LayoutSuppressingImageView
+ android:id="@+id/contact_tile_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/contact_tile_shadowbox_height"
+ android:orientation="vertical"
+ android:background="@color/contact_tile_shadow_box_color"
+ android:layout_alignParentBottom="true"
+ android:gravity="center_vertical"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:paddingStart="8dip"
+ android:paddingEnd="8dip">
+
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/white"
+ android:textSize="16sp"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:ellipsize="marquee"
+ android:textAlignment="viewStart" />
+
+ <TextView
+ android:id="@+id/contact_tile_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@color/people_contact_tile_status_color"
+ android:singleLine="true"
+ android:drawablePadding="4dip"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="3dip"
+ android:layout_marginTop="-3dip"
+ android:ellipsize="marquee" />
+
+ </LinearLayout>
+
+ <QuickContactBadge
+ android:id="@+id/contact_tile_quick"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:background="@null" />
+
+ </RelativeLayout>
+
+</view>
diff --git a/res/layout/custom_contact_list_filter_account.xml b/res/layout/custom_contact_list_filter_account.xml
new file mode 100644
index 0000000..c7a6cb5
--- /dev/null
+++ b/res/layout/custom_contact_list_filter_account.xml
@@ -0,0 +1,60 @@
+<?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="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingLeft="@dimen/contact_filter_list_item_padding_start"
+ android:paddingRight="?android:attr/scrollbarSize"
+ android:paddingStart="@dimen/contact_filter_list_item_padding_start"
+ android:paddingEnd="?android:attr/scrollbarSize">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="6dip"
+ android:layout_marginEnd="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/textAppearanceListItem"
+ 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:layout_alignStart="@android:id/text1"
+ android:maxLines="1"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:textColor="?android:attr/textColorTertiary"
+ android:duplicateParentState="true" />
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/res/layout/custom_contact_list_filter_group.xml b/res/layout/custom_contact_list_filter_group.xml
new file mode 100644
index 0000000..c67ce16
--- /dev/null
+++ b/res/layout/custom_contact_list_filter_group.xml
@@ -0,0 +1,90 @@
+<?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="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/contact_filter_list_item_height"
+ android:gravity="center_vertical"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/contact_filter_list_item_height"
+ android:gravity="center_vertical"
+ android:paddingLeft="@dimen/contact_filter_list_item_padding_start"
+ android:paddingRight="?android:attr/scrollbarSize"
+ android:paddingStart="@dimen/contact_filter_list_item_padding_start"
+ android:paddingEnd="?android:attr/scrollbarSize">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="6dip"
+ android:layout_marginEnd="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/textAppearanceListItem"
+ android:textColor="@color/account_filter_text_color"
+ 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:layout_alignStart="@android:id/text1"
+ android:maxLines="2"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:textColor="@color/account_filter_text_color"
+ android:duplicateParentState="true"
+ />
+
+ </RelativeLayout>
+
+ <CheckBox
+ android:id="@android:id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="false"
+ android:clickable="false"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:duplicateParentState="true"
+ />
+
+ </LinearLayout>
+
+ <View
+ android:id="@+id/adapter_divider_bottom"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@color/custom_filter_divider" />
+
+</LinearLayout>
diff --git a/res/layout/default_account_checkbox.xml b/res/layout/default_account_checkbox.xml
new file mode 100644
index 0000000..9a1a450
--- /dev/null
+++ b/res/layout/default_account_checkbox.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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/default_account_checkbox_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="4dp"
+ android:orientation="vertical">
+ <CheckBox
+ android:id="@+id/default_account_checkbox_view"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="15dip"
+ android:layout_marginLeft="13dip"
+ android:layout_marginBottom="20dip"
+ android:gravity="center"
+ android:textAlignment="viewStart"
+ android:text="@string/set_default_account"
+ android:textColor="@color/dialtacts_secondary_text_color"
+ />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/dialog_call_subject.xml b/res/layout/dialog_call_subject.xml
new file mode 100644
index 0000000..d6365c2
--- /dev/null
+++ b/res/layout/dialog_call_subject.xml
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"
+ android:id="@+id/call_subject_dialog"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layout_width="match_parent">
+
+ <!-- The call subject dialog will be centered in the space above the subject list. -->
+ <LinearLayout
+ android:id="@+id/dialog_view"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:theme="@android:style/Theme.Material.Light.Dialog"
+ android:elevation="16dp"
+ android:layout_centerInParent="true"
+ android:background="@drawable/dialog_background_material">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginStart="@dimen/call_subject_dialog_margin"
+ android:layout_marginEnd="@dimen/call_subject_dialog_margin"
+ android:layout_marginTop="@dimen/call_subject_dialog_margin">
+
+ <QuickContactBadge
+ android:id="@+id/contact_photo"
+ android:layout_width="@dimen/call_subject_dialog_contact_photo_size"
+ android:layout_height="@dimen/call_subject_dialog_contact_photo_size"
+ android:layout_gravity="top"
+ android:focusable="true"
+ android:layout_marginEnd="@dimen/call_subject_dialog_margin" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_vertical">
+
+ <TextView
+ android:id="@+id/name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/dialtacts_primary_text_color"
+ android:textSize="@dimen/call_subject_dialog_secondary_text_size"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/number"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginTop="@dimen/call_subject_dialog_between_line_margin"
+ android:textColor="@color/dialtacts_secondary_text_color"
+ android:textSize="@dimen/call_subject_dialog_secondary_text_size"
+ android:singleLine="true" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <EditText
+ android:id="@+id/call_subject"
+ android:hint="@string/call_subject_hint"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layout_gravity="top"
+ android:textColor="@color/dialtacts_secondary_text_color"
+ android:textSize="@dimen/call_subject_dialog_secondary_text_size"
+ android:gravity="top"
+ android:background="@null"
+ android:layout_marginTop="@dimen/call_subject_dialog_edit_spacing"
+ android:layout_marginStart="@dimen/call_subject_dialog_margin"
+ android:layout_marginEnd="@dimen/call_subject_dialog_margin"
+ />
+
+ <TextView
+ android:id="@+id/character_limit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/dialtacts_secondary_text_color"
+ android:textSize="@dimen/call_subject_dialog_secondary_text_size"
+ android:singleLine="true"
+ android:layout_marginStart="@dimen/call_subject_dialog_margin"
+ android:layout_marginEnd="@dimen/call_subject_dialog_margin"
+ android:layout_marginTop="@dimen/call_subject_dialog_margin"
+ android:layout_marginBottom="@dimen/call_subject_dialog_margin"/>
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1dp"
+ android:background="@color/call_subject_divider"/>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/call_subject_dialog_margin"
+ android:layout_marginEnd="@dimen/call_subject_dialog_margin"
+ android:layout_marginTop="@dimen/call_subject_dialog_margin"
+ android:layout_marginBottom="@dimen/call_subject_dialog_margin">
+
+ <ImageView
+ android:id="@+id/history_button"
+ android:layout_width="25dp"
+ android:layout_height="25dp"
+ android:src="@drawable/ic_history_white_drawable_24dp"
+ android:tint="@color/call_subject_history_icon"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true" />
+
+ <TextView
+ android:id="@+id/send_and_call_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/send_and_call_button"
+ android:textColor="@color/call_subject_button"
+ android:textSize="@dimen/call_subject_dialog_secondary_text_size"
+ android:singleLine="true"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true" />
+
+ </RelativeLayout>
+ </LinearLayout>
+ </RelativeLayout>
+ <!-- The subject list is pinned to the bottom of the screen. -->
+ <ListView
+ android:id="@+id/subject_list"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_below="@id/dialog_view"
+ android:background="@color/call_subject_history_background"
+ android:divider="@null"
+ android:elevation="8dp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/dialog_title.xml b/res/layout/dialog_title.xml
new file mode 100644
index 0000000..b88f47c
--- /dev/null
+++ b/res/layout/dialog_title.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="18dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:textSize="20sp"
+ android:textColor="@color/contacts_text_color"
+ android:fontFamily="sans-serif-medium"
+ android:ellipsize="end"
+/>
\ No newline at end of file
diff --git a/res/layout/directory_header.xml b/res/layout/directory_header.xml
new file mode 100644
index 0000000..3e41aa7
--- /dev/null
+++ b/res/layout/directory_header.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.
+-->
+
+<!-- Layout used for list section separators. -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/DirectoryHeader"
+ android:id="@+id/directory_header"
+ android:background="?attr/contact_browser_background"
+ android:paddingLeft="@dimen/directory_header_left_padding"
+ android:paddingRight="?attr/list_item_padding_right"
+ android:paddingStart="@dimen/directory_header_left_padding"
+ android:paddingEnd="?attr/list_item_padding_right"
+ android:paddingTop="@dimen/directory_header_extra_top_padding"
+ android:paddingBottom="@dimen/directory_header_extra_bottom_padding"
+ android:minHeight="@dimen/list_section_divider_min_height"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ <TextView
+ android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/DirectoryHeaderStyle"
+ android:singleLine="true"
+ android:textAlignment="viewStart" />
+ <TextView
+ android:id="@+id/display_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:textAppearance="@style/DirectoryHeaderStyle"
+ android:singleLine="true"
+ android:textAlignment="viewStart" />
+ <TextView
+ android:id="@+id/count"
+ android:paddingTop="1dip"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:singleLine="true"
+ android:textAppearance="@style/DirectoryHeaderStyle" />
+</LinearLayout>
diff --git a/res/layout/editor_save_button.xml b/res/layout/editor_save_button.xml
new file mode 100644
index 0000000..024ddcb
--- /dev/null
+++ b/res/layout/editor_save_button.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ style="?android:attr/buttonBarButtonStyle"
+ android:id="@+id/editor_menu_save_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/menu_save"
+ android:textColor="@color/action_bar_button_text_color"
+ android:textSize="14sp">
+</Button>
diff --git a/res/layout/floating_action_button.xml b/res/layout/floating_action_button.xml
index 95c76ae..2dc8955 100644
--- a/res/layout/floating_action_button.xml
+++ b/res/layout/floating_action_button.xml
@@ -14,24 +14,26 @@
limitations under the License.
-->
-<!-- This expects to be included inside a RelativeLayout -->
+<!-- This expects to be included inside a RelativeLayout or a CoordinatorLayout -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/floating_action_button_container"
android:layout_width="@dimen/floating_action_button_width"
android:layout_height="@dimen/floating_action_button_height"
- android:layout_marginEnd="@dimen/floating_action_button_margin_right"
- android:layout_marginBottom="@dimen/floating_action_button_margin_bottom"
- android:background="@drawable/fab_blue"
+ android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
- android:layout_alignParentBottom="true">
+ android:layout_gravity="bottom|end"
+ android:layout_marginBottom="@dimen/floating_action_button_margin_bottom"
+ android:layout_marginEnd="@dimen/floating_action_button_margin_right"
+ android:background="@drawable/fab_blue"
+ android:elevation="@dimen/design_fab_elevation">
<ImageButton
android:id="@+id/floating_action_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/floating_action_button"
- android:tint="@color/floating_action_button_icon_color"
android:contentDescription="@string/action_menu_add_new_contact_button"
- android:src="@drawable/ic_add"/>
+ android:src="@drawable/ic_add"
+ android:tint="@color/floating_action_button_icon_color"/>
</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/group_name_dialog.xml b/res/layout/group_name_dialog.xml
deleted file mode 100644
index f19df86..0000000
--- a/res/layout/group_name_dialog.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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.
--->
-
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingLeft="25dip"
- android:paddingRight="25dip"
- android:paddingStart="25dip"
- android:paddingEnd="25dip"
- android:paddingTop="25dip"
- android:paddingBottom="25dip">
- <EditText
- android:id="@+id/group_label"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/group_name_edit_text_min_height"/>
-</FrameLayout>
diff --git a/res/layout/group_name_edit_dialog.xml b/res/layout/group_name_edit_dialog.xml
index 9a8c69f..5df8c9d 100644
--- a/res/layout/group_name_edit_dialog.xml
+++ b/res/layout/group_name_edit_dialog.xml
@@ -14,24 +14,28 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.design.widget.TextInputLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/text_input_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingBottom="24dp"
+ android:paddingEnd="24dp"
android:paddingStart="24dp"
- android:paddingEnd="24dp">
+ app:errorEnabled="true"
+ app:hintEnabled="false">
- <EditText android:id="@android:id/text1"
- xmlns:android="http://schemas.android.com/apk/res/android"
+ <android.support.design.widget.TextInputEditText
+ android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="@dimen/group_name_edit_text_min_height"
android:layout_marginBottom="4dp"
android:layout_marginRight="4dp"
android:layout_marginTop="16dp"
android:hint="@string/group_name_dialog_hint"
android:inputType="text"
- android:singleLine="true"
- android:maxLength="@integer/group_name_max_length"/>
-</LinearLayout>
\ No newline at end of file
+ android:maxLength="@integer/group_name_max_length"
+ android:minHeight="@dimen/group_name_edit_text_min_height"
+ android:singleLine="true"/>
+</android.support.design.widget.TextInputLayout>
\ No newline at end of file
diff --git a/res/layout/licenses.xml b/res/layout/licenses.xml
new file mode 100644
index 0000000..66d4f46
--- /dev/null
+++ b/res/layout/licenses.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 Google Inc. All Rights Reserved. -->
+
+<WebView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/webview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+</WebView>
\ No newline at end of file
diff --git a/res/layout/list_separator.xml b/res/layout/list_separator.xml
new file mode 100644
index 0000000..80abacb
--- /dev/null
+++ b/res/layout/list_separator.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/title"
+ android:textColor="@color/frequently_contacted_title_color"
+ android:paddingLeft="16dip"
+ android:paddingStart="16dip"
+ android:paddingRight="16dip"
+ android:paddingEnd="16dip"
+ android:paddingBottom="15dip"
+ android:paddingTop="16dip"
+ android:textStyle="bold"
+ android:textSize="@dimen/frequently_contacted_title_text_size"/>
diff --git a/res/layout/search_bar_expanded.xml b/res/layout/search_bar_expanded.xml
new file mode 100644
index 0000000..ecadbd1
--- /dev/null
+++ b/res/layout/search_bar_expanded.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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/search_box_expanded"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:visibility="gone" >
+
+ <ImageButton
+ android:id="@+id/search_back_button"
+ android:layout_width="@dimen/search_box_icon_size"
+ android:layout_height="@dimen/search_box_icon_size"
+ android:layout_marginEnd="@dimen/search_box_navigation_icon_margin"
+ android:src="@drawable/ic_back_arrow"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/action_menu_back_from_search"
+ android:tint="@color/actionbar_background_color" />
+
+ <android.widget.AutoCompleteTextView
+ android:id="@+id/search_view"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/search_box_icon_size"
+ android:layout_weight="1"
+ android:layout_marginLeft="@dimen/search_box_text_left_margin"
+ android:textSize="@dimen/search_text_size"
+ android:fontFamily="@string/search_font_family"
+ android:textColor="@color/searchbox_text_color"
+ android:textColorHint="@color/searchbox_hint_text_color"
+ android:textCursorDrawable="@drawable/searchedittext_custom_cursor"
+ android:background="@null"
+ android:inputType="textFilter"
+ android:singleLine="true"
+ android:imeOptions="flagNoExtractUi" />
+
+ <ImageView
+ android:id="@+id/search_close_button"
+ android:layout_height="@dimen/search_box_close_icon_size"
+ android:layout_width="@dimen/search_box_close_icon_size"
+ android:padding="@dimen/search_box_close_icon_padding"
+ android:src="@drawable/ic_close_black_24dp"
+ android:clickable="true"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/description_clear_search"
+ android:alpha="@dimen/close_icon_alpha" />
+
+</LinearLayout>
diff --git a/res/layout/select_account_list_item.xml b/res/layout/select_account_list_item.xml
new file mode 100644
index 0000000..0ba4336
--- /dev/null
+++ b/res/layout/select_account_list_item.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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 of a single item in the InCallUI Account Chooser Dialog. -->
+<view class="com.android.contacts.common.widget.ActivityTouchLinearLayout"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="8dp" >
+
+ <ImageView android:id="@+id/icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:scaleType="center" />
+
+ <LinearLayout
+ android:id="@+id/text"
+ android:gravity="start|center_vertical"
+ android:layout_marginLeft="8dp"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+ <TextView android:id="@+id/label"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/dialtacts_primary_text_color"
+ android:includeFontPadding="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ <TextView android:id="@+id/number"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:includeFontPadding="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+ </LinearLayout>
+
+</view>
diff --git a/res/layout/select_dialog_item.xml b/res/layout/select_dialog_item.xml
new file mode 100644
index 0000000..0c524fd
--- /dev/null
+++ b/res/layout/select_dialog_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<!--
+ List item in the pop-up window that appears when tapping a contact's photo
+ in the contact editor. This is similar to the framework's select_dialog_item_material.xml layout
+ except the text appearance is medium and the padding is set to match the material spec.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:textAlignment="viewStart"
+ android:textColor="@color/contacts_text_color"
+ android:textSize="16sp"
+ android:gravity="center_vertical"
+ android:paddingStart="24dip"
+ android:paddingEnd="24dip"
+ android:ellipsize="marquee" />
\ No newline at end of file
diff --git a/res/layout/unread_count_tab.xml b/res/layout/unread_count_tab.xml
new file mode 100644
index 0000000..783f1c1
--- /dev/null
+++ b/res/layout/unread_count_tab.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/view_pager_tab_background">
+ <!-- The tab icon -->
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true" />
+ <TextView
+ android:id="@+id/count"
+ android:background="@drawable/unread_count_background"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/tab_unread_count_background_size"
+ android:gravity="center"
+ android:minWidth="@dimen/tab_unread_count_background_size"
+ android:layout_marginStart="@dimen/tab_unread_count_margin_left"
+ android:layout_marginTop="@dimen/tab_unread_count_margin_top"
+ android:layout_toEndOf="@id/icon"
+ android:paddingLeft="@dimen/tab_unread_count_text_padding"
+ android:paddingRight="@dimen/tab_unread_count_text_padding"
+ android:textAlignment="center"
+ android:textSize="@dimen/tab_unread_count_text_size"
+ android:textColor="@color/tab_accent_color"
+ android:fontFamily="sans-serif-medium"
+ android:importantForAccessibility="no" />
+</RelativeLayout>
diff --git a/res/menu/edit_contact.xml b/res/menu/edit_contact.xml
index 256edb6..9bf067f 100644
--- a/res/menu/edit_contact.xml
+++ b/res/menu/edit_contact.xml
@@ -18,7 +18,7 @@
<item
android:id="@+id/menu_save"
android:showAsAction="always"
- android:icon="@drawable/ic_done_wht_24dp"
+ android:actionLayout="@layout/editor_save_button"
android:title="@string/menu_save" />
<item
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 8b73bad..82bc789 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Stel verstek op"</string>
<string name="clear_default" msgid="7193185801596678067">"Vee verstek uit"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Teks gekopieer"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Gooi jou veranderings weg en hou op om te wysig?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Ignoreer veranderinge?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Gooi weg"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Hou aan wysig"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Kanselleer"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Deursoek kontakte"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Verwyder kontakte"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Meer oor"</string>
<string name="send_message" msgid="8938418965550543196">"Stuur boodskap"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Skep tans \'n persoonlike kopie..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Gister"</string>
<string name="tomorrow" msgid="6241969467795308581">"Môre"</string>
<string name="today" msgid="8041090779381781781">"Vandag"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Vandag om <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Boodskappe"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organiseer jou lys"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Vee duplikate uit en groepeer kontakte volgens etiket"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Teks gekopieer"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopieer na knipbord"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Bel <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Bel tuis"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Bel selfoon"</string>
+ <string name="call_work" msgid="5328785911463744028">"Bel werk"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Bel werkfaks"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Bel huisfaks"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Bel roeper"</string>
+ <string name="call_other" msgid="8563753966926932052">"Bel"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Bel - terugbel"</string>
+ <string name="call_car" msgid="3280537320306436445">"Bel motor"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Bel maatskappy, hoof"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Bel ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Bel hoof"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Bel faks"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Bel radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Bel teleks"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Oproep-TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Bel werkselfoon"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Bel werkroeper"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Bel <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Bel MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Teks <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Teks - tuis"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Teks - selfoon"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Teks - werk"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Teks - werkfaks"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Teks - huisfaks"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Teks - roeper"</string>
+ <string name="sms_other" msgid="806127844607642331">"Teks"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Teks-terugbel"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Teks - motor"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Teks - maatskappy, hoof"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Teks - ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Teks - hoof"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Teksfaks"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Teks - radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Teks - teleks"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Teks - TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Teks - werkselfoon"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Teks - werkroeper"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Teks <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Teks - MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Vee dikwels-gebruikte kontakte uit?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Vee tans dikwels-gebruikte kontakte uit..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Beskikbaar"</string>
+ <string name="status_away" msgid="1838861100379804730">"Weg"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Besig"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontakte"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Ander"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Gids"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Alle kontakte"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Soek tans…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Meer as <xliff:g id="COUNT">%d</xliff:g> gevind."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Geen kontakte nie"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> gevind</item>
+ <item quantity="one">1 gevind</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Vinnige kontak vir <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Geen naam nie)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Gereeld gekontak"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Bekyk kontak"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Alle kontakte met telefoonnommers"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Sien opdaterings"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Naam"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Bynaam"</string>
+ <string name="full_name" msgid="6602579550613988977">"Naam"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Naamvoorvoegsel"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Middelnaam"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Naamagtervoegsel"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Fonetiese naam"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetiese middelnaam"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Foon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-pos"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adres"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisasie"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Verhouding"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Teksboodskap"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adres"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Maatskappy"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titel"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notas"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Webwerf"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"E-postuis"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-pos - mobiel"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-pos - werk"</string>
+ <string name="email_other" msgid="3454004077967657109">"E-pos"</string>
+ <string name="email_custom" msgid="7548003991586214105">"E-pos <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-pos"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Straat"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Posbus"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Buurt"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Stad"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Deelstaat"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Poskode"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Land"</string>
+ <string name="map_home" msgid="1243547733423343982">"Sien huisadres"</string>
+ <string name="map_work" msgid="1360474076921878088">"Sien werkadres"</string>
+ <string name="map_other" msgid="3817820803587012641">"Sien adres"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Sien <xliff:g id="CUSTOM">%s</xliff:g> adres"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Klets met AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Klets met Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Klets met Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Klets met Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Klets met QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Klets met Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Klets met ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Klets met Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Klets"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"vee uit"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Vou naamvelde uit of in"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Alle kontakte"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Gester"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Pasmaak"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontak"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Alle ander kontakte"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Alle kontakte"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Verwyder sinkroniseergroep"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Voeg sinkroniseergroep by"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Meer groepe..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"As jy \'<xliff:g id="GROUP">%s</xliff:g>\' uit sinkronisering verwyder, sal dit ook enige ongegroepeerde kontakte uit sinkronisering verwyder."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Stoor tans vertoonopsies..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Klaar"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Kanselleer"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Voer in van SIM-kaart"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Kanselleer invoer van <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Kanselleer uitvoer van <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Kon nie vCard invoer/uitvoer kanselleer nie"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Onbekende fout"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Kon nie \"<xliff:g id="FILE_NAME">%s</xliff:g>\" open nie: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Kon nie die uitvoerder aktiveer nie: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Daar is geen uitvoerbare kontak nie."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"\'n Fout het voorgekom tydens uitvoer: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Vereiste lêernaam is te lank (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"T/A-fout"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Nie genoeg geheue nie. Die lêer is dalk te groot."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Kon nie vCard ontleed nie weens onverwagte redes."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Die formaat word nie ondersteun nie."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Kon nie meta-inligting van gegewe vCard-lêer(s) versamel nie."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Een of meer lêers kon nie ingevoer word nie (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Het <xliff:g id="FILENAME">%s</xliff:g> klaar uitgevoer."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Uitvoer van <xliff:g id="FILENAME">%s</xliff:g> is gekanselleer."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Voer kontakdata uit"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Kon nie databasis-inligting kry nie"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Daar is geen kontakte om uit te voer nie. As jy kontakte op jou foon het, sal sommige dataverskaffers nie toelaat dat die foon se kontakte uitgevoer word nie."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Die vCard-opsteller het nie behoorlik begin nie."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Kon nie uitvoer nie"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Die kontakdata is nie uitgevoer nie.\nRede: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Voer <xliff:g id="NAME">%s</xliff:g> in"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Kon nie vCard-data lees nie"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Lees van vCard-data gekanselleer"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Klaar met invoer van vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Invoer van <xliff:g id="FILENAME">%s</xliff:g> gekanselleer"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> sal binnekort ingevoer word."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Die lêer sal binnekort ingevoer word."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard-invoerversoek is verwerp. Probeer asseblief later weer."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> sal binnekort uitgevoer word."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard-uitvoerversoek is verwerp. Probeer asseblief later."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontak"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Kas van vCard(s) na die die plaaslike tydelike stoor. Die werklike invoer sal binnekort begin."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Kon nie vCard invoer nie."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontak ontvang via NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Voer kontakte uit?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Kas tans..."</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Voer <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g> in: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Instellings"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Deel sigbare kontakte"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Voer kontakte in/uit"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Voer kontakte in"</string>
+ <string name="share_error" msgid="948429331673358107">"Hierdie kontak kan nie gedeel word nie."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Soek"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kontakte om te wys"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kontakte om te wys"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Gunstelinge"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Geen kontakte nie."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Vee dikwels-gebruiktes uit"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Kies SIM-kaart"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Voer in/uit"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Geblokkeerde nommers"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Vee soektog uit"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 1bfc997..4a08098 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"ነባሪ አዘጋጅ"</string>
<string name="clear_default" msgid="7193185801596678067">"ነባሪ አጽዳ"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"ፅሁፍ ገልብጧል"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"ለውጦችዎ ይወገዱ እና ማርትዕ ይቁም?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"ለውጦች ይወገዱ?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"አስወግድ"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"አርትዖቱን ቀጥል"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"ተወው"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"እውቅያዎችን ፈልግ"</string>
<string name="title_edit_group" msgid="8602752287270586734">"ዕውቂያዎችን ያስወግዱ"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"ስለ"</string>
<string name="send_message" msgid="8938418965550543196">"መልዕክት ላክ"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"የግል ቅጂ በመፍጠር ላይ..."</string>
- <string name="yesterday" msgid="6840858548955018569">"ትላንት"</string>
<string name="tomorrow" msgid="6241969467795308581">"ነገ"</string>
<string name="today" msgid="8041090779381781781">"ዛሬ"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"ዛሬ <xliff:g id="TIME_INTERVAL">%s</xliff:g> ላይ"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"መልእክቶች"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"ዝርዝርዎን ያደራጁ"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"ተደጋጋሚዎችን ያጽዱ፤ እንዲሁም እውቂያዎችን በመሰየሚያ ያቧድኑ።"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"ፅሁፍ ገልብጧል"</string>
+ <string name="copy_text" msgid="3257145021583508761">"ወደ ቅንጥብ ሰሌዳ ገልብጥ"</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="8563753966926932052">"ደውል"</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="5745314124619636674">"ፋክስ ደውል"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"ፅሁፍ"</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="3888842199855843152">"የፋክስ ፅሁፍ"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"በተደጋጋሚ ያገኝዋቸው ይጽዱ?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"በተደጋጋሚ ያገኘሃቸውን በመጥረግ ላይ…"</string>
+ <string name="status_available" msgid="5586870015822828392">"የሚገኝ"</string>
+ <string name="status_away" msgid="1838861100379804730">"ወጣ ብሏል"</string>
+ <string name="status_busy" msgid="9147992455450257136">"ተይዟ ል"</string>
+ <string name="contactsList" msgid="8661624236494819731">"እውቅያዎች"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"ሌላ"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">" ማውጫ"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"ሁሉም እውቅያዎች"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"በመፈለግ ላይ…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"ከ<xliff:g id="COUNT">%d</xliff:g> የበለጠ ተገኝቷል"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"እውቅያዎች የሉም"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ተገኝቷል</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ተገኝቷል</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"ለ <xliff:g id="NAME">%1$s</xliff:g> ፈጣን ዕውቂያ"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(ስም የለም)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"በተደጋጋሚ የሚገናኙ"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"ዕውቂያ ዕይ"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"የስልክ ቁጥር ያላቸው ሁሉም ዕውቂያዎች"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"አዘምኖችን ዕይ"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"ስም"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"ቅጽል ስም"</string>
+ <string name="full_name" msgid="6602579550613988977">"ስም"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"የድምፀ ልሳን ስም"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"የድምፀ ልሳንመካከለኛ ስም"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"ስልክ"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"ኢሜይል"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"አድራሻ"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"ፈጣን መልዕክቶች"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"መስርያ ቤት"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"ግንኙነት"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"የጽሑፍ መልዕክት"</string>
+ <string name="postal_address" msgid="8765560217149624536">"አድራሻ"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"ኩባንያ"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"አርዕስት"</string>
+ <string name="label_notes" msgid="8337354953278341042">"ማስታወሻዎች"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"ድረ ገፅ"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"ኢሜይል"</string>
+ <string name="email_custom" msgid="7548003991586214105">"ኢሜይል <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"ኢሜይል"</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="map_home" msgid="1243547733423343982">"የመነሻ አድራሻ ዕይ"</string>
+ <string name="map_work" msgid="1360474076921878088">"የሥራ አድራሻ ዕይ"</string>
+ <string name="map_other" msgid="3817820803587012641">"አድራሻ እይ"</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="description_minus_button" msgid="6908099247930477551">"ሰርዝ"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"የስም መስኮችን ይዘርጉ ወይም ይሰብስቡ"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"ሁሉም እውቅያዎች"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"ኮከብ የተደረገባቸው"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"ብጁ አድርግ"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"እውቅያ"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"ሌላ ሁሉም ዕውቂያዎች"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"ሁሉም እውቅያዎች"</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_warn_remove_ungrouped" msgid="8872290721676651414">"\'<xliff:g id="GROUP">%s</xliff:g>\' ከአሳምር ማስወገድ እንዲሁ ማንኛውም በተነጣጥል ያሉ ዕውቅያዎችን ከአሳምር ያስወግዳል።"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"ማሳያ አማራጮችን በማስቀመጥ ላይ..."</string>
+ <string name="menu_done" msgid="796017761764190697">"ተከናውኗል"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"ይቅር"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"ከSIM ካርድ አስመጣ"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"የ<xliff:g id="FILENAME">%s</xliff:g>ወደ ውስጥ ማስገባት ይቅር?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"የ<xliff:g id="FILENAME">%s</xliff:g> ወደ ውጭ መላክ ይቅር?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard ማስመጣት/ወደ ውጪ መላክ ይቅር ማለት አልተቻለም"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"ያልታወቀ ስህተት"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" ፡<xliff:g id="EXACT_REASON">%s</xliff:g> መክፈት አልተቻለም"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"ላኪው፡\"<xliff:g id="EXACT_REASON">%s</xliff:g>\" ለማስነሳት አልተቻለም"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"ምንም ወደ ውጭ መላክ የሚችል ዕውቂያ የለም"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"በመላክ ጊዜስህተት ተከስቷል: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"የተጠየቀው ፋይል ስም በጣም ረጅም ነው (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O ስህተት"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"በቂ ማህደረ ትውስታ የለም፡፡ፋይሉ ምናልባት በጣም ትልቅ ይሆናል፡፡"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"ባልተጠበቀ ምክንያት vCard መተንተን አልተቻለም፡፡"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"ቅርፀቱ አይታገዝም"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"በተሰጠው(ጡት) vCard ፋይል(ሎች) ሜታ መረጃ መሰብሰብ አልተቻለም፡፡"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"አንድ ወይም ከዛ በላይ ፋይሎች ማስመጣት አልተቻለም (%s)፡፡"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> መላክ ጨርሷል"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"መላክ <xliff:g id="FILENAME">%s</xliff:g> ተሰርዟል::"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"የዕውቂያ ውሂብ በመላክ ላይ"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"ውሂብ ጎታ መረጃን ማግኘት አልተቻለም"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"ወደ ውጭ የሚላኩ እውቅያዎች የሉም፡፡ ስልክህ ውስጥ እውቅያዎች ካሉህ፤አንዳንድ ውሂብ አቅራቢዎች ከስልኩ እውቅያዎች ወደ ውጭ እንዲላኩ አይፈቅዱም፡፡"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"የ vCard አቀናባሪው በትክክል አልጀመረም::"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"ወደ ውጭ መላክ አልተቻለም"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"የዕውቅያ ውሂብ ወደ ውጭ አልተላከም፡፡ \nምክንያት፡፡\"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> ማስገባት"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard ውሂብ ማንበብ አልተቻለም"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"የvCard ውሂብ ማንበብ ተሰርዟል"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">" <xliff:g id="FILENAME">%s</xliff:g> vCard ማስመጣት ጨርሷል"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> ማስመጣት ተሰርዞዋል"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> ከአፍታ ቆይታ በኋላ ይመጣል።"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"ፋይሉ ከአፍታ ቆይታ በኋላ ይመጣል።"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"የvCard ማስመጣት ጥየቃ ውድቅ ተደርጓል። እባክህ ትንሽ ቆይተህ ሞክር።"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> ከአፍታ ቆይታ በኋላ ይላካል።"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"የvCard ላክ ጥየቃ ውድቅ ተደርጓል። እባክህ ትንሽ ቆይተህ ሞክር።"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"እውቅያ"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"ወደ ጊዜያዊ ማከማቻ vCard(s) እየሸጎጠ ነው። ትክክለኛው አስመጣ በቅርቡ ይጀምራል።"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard ማስመጣት አልተቻለም"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"በ NFC የደረሱ ዕውቂያዎች"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"እውቅያዎች ላክ"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"በመሸጎጥ ላይ"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"በማስገባት ላይ<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>፡<xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"ቅንብሮች"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"የሚታዩ እውቂያዎችን አጋራ"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"ዕውቂያዎች አስመጣ/ላክ"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"እውቅያዎችን ከውጭ አስመጣ"</string>
+ <string name="share_error" msgid="948429331673358107">"ይህ ዕውቂያ መጋራት አይችልም።"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"ፍለጋ"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"ዕውቂያዎች አሳይ"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"ዕውቂያዎች አሳይ"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"ተወዳጆች"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"ምንም ዕውቂያዎች የሉም"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"ተደጋጋሚዎችን አጽዳ"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"ሲም ካርድ ይምረጡ"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"አስመጣ/ላክ"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"የታገዱ ቁጥሮች"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"በ<xliff:g id="SOURCE">%1$s</xliff:g> በኩል"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g>በ<xliff:g id="SOURCE">%2$s</xliff:g> በኩል"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"ፍለጋን አጽዳ"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 0df6033..285d869 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -260,9 +260,9 @@
<string name="set_default" msgid="4417505153468300351">"تعيين كافتراضي"</string>
<string name="clear_default" msgid="7193185801596678067">"محو الإعدادات الافتراضية"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"تم نسخ النص"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"هل تريد تجاهل التغييرات ومغادرة التعديل؟"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"هل تريد إلغاء التغييرات؟"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"تجاهل"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"متابعة التعديلات"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"إلغاء"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"البحث في جهات الاتصال"</string>
<string name="title_edit_group" msgid="8602752287270586734">"إزالة جهات الاتصال"</string>
@@ -287,7 +287,6 @@
<string name="about_card_title" msgid="2920942314212825637">"حول"</string>
<string name="send_message" msgid="8938418965550543196">"إرسال رسالة"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"جارٍ إنشاء نسخة شخصية..."</string>
- <string name="yesterday" msgid="6840858548955018569">"أمس"</string>
<string name="tomorrow" msgid="6241969467795308581">"غدًا"</string>
<string name="today" msgid="8041090779381781781">"اليوم"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"اليوم في <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -386,4 +385,338 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"الرسائل"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"ترتيب قائمتك"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"إزالة النُسخ طبق الأصل وجهات اتصال المجموعات حسب التصنيف"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"تم نسخ النص"</string>
+ <string name="copy_text" msgid="3257145021583508761">"نسخ إلى الحافظة"</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="8563753966926932052">"اتصال"</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="5745314124619636674">"الاتصال برقم الفاكس"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"إرسال رسالة نصية"</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="3888842199855843152">"إرسال رسالة إلى فاكس"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"هل تريد محو قائمة من يُتصل بهم كثيرًا؟"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"جارٍ محو قائمة المُتصل بهم كثيرًا…"</string>
+ <string name="status_available" msgid="5586870015822828392">"متوفر"</string>
+ <string name="status_away" msgid="1838861100379804730">"بعيد"</string>
+ <string name="status_busy" msgid="9147992455450257136">"مشغول"</string>
+ <string name="contactsList" msgid="8661624236494819731">"جهات الاتصال"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"غير ذلك"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"الدليل"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"جميع جهات الاتصال"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"جارٍ البحث..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"تم العثور على أكثر من <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"ليست هناك جهات اتصال"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="zero">لا توجد أي جهة اتصال (<xliff:g id="COUNT">%d</xliff:g>)</item>
+ <item quantity="two">توجد جهتا اتصال (<xliff:g id="COUNT">%d</xliff:g>)</item>
+ <item quantity="few">توجد <xliff:g id="COUNT">%d</xliff:g> جهات اتصال</item>
+ <item quantity="many">توجد <xliff:g id="COUNT">%d</xliff:g> جهة اتصال</item>
+ <item quantity="other">توجد <xliff:g id="COUNT">%d</xliff:g> من جهات الاتصال</item>
+ <item quantity="one">توجد جهة اتصال واحدة</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"اتصال سريع لـ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(بلا اسم)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"يتم الاتصال بهم بشكل متكرر"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"عرض جهة الاتصال"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"جميع جهات الاتصال التي لها أرقام هواتف"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"عرض التحديثات"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"الاسم"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"اللقب"</string>
+ <string name="full_name" msgid="6602579550613988977">"الاسم"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"الاسم"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"الاسم الصوتي الأوسط"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"الهاتف"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"البريد الإلكتروني"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"العنوان"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"المراسلة الفورية"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"المؤسسة"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"العلاقة"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"رسالة نصية"</string>
+ <string name="postal_address" msgid="8765560217149624536">"العنوان"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"شركة"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"المسمى الوظيفي"</string>
+ <string name="label_notes" msgid="8337354953278341042">"ملاحظات"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"موقع ويب"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"بريد إلكتروني"</string>
+ <string name="email_custom" msgid="7548003991586214105">"البريد الإلكتروني <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"بريد إلكتروني"</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="map_home" msgid="1243547733423343982">"عرض عنوان المنزل"</string>
+ <string name="map_work" msgid="1360474076921878088">"عرض عنوان العمل"</string>
+ <string name="map_other" msgid="3817820803587012641">"عرض عنوان"</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="description_minus_button" msgid="6908099247930477551">"حذف"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"توسيع أو تصغير حقول الاسم"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"جميع جهات الاتصال"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"مميّزة بنجمة"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"تخصيص"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"جهة الاتصال"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"جميع جهات الاتصال الأخرى"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"جميع جهات الاتصال"</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_warn_remove_ungrouped" msgid="8872290721676651414">"ستؤدي إزالة \"<xliff:g id="GROUP">%s</xliff:g>\" من المزامنة أيضًا إلى إزالة أية جهات اتصال غير مجمعة من المزامنة."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"جارٍ حفظ خيارات العرض..."</string>
+ <string name="menu_done" msgid="796017761764190697">"تم"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"إلغاء"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"استيراد من شريحة SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"هل تريد إلغاء استيراد <xliff:g id="FILENAME">%s</xliff:g>؟"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"هل تريد إلغاء تصدير <xliff:g id="FILENAME">%s</xliff:g>؟"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"تعذر إلغاء استيراد/تصدير vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"خطأ غير معروف."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"تعذر فتح \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"تعذر بدء المُصدر: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"ليست هناك جهة اتصال قابلة للتصدير."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"حدث خطأ أثناء التصدير: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"اسم الملف المطلوب أطول مما يجب (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"خطأ I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"الذاكرة غير كافية. ربما يكون الملف أكبر مما يجب."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"تعذر تحليل vCard بسبب غير متوقع."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"التنسيق غير معتمد."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"تعذر جمع معلومات وصفية حول ملفات vCard المحددة."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"تعذر استيراد ملف أو أكثر (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"تم الانتهاء من تصدير <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"تم إلغاء تصدير <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"تصدير بيانات جهة الاتصال"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"تعذر الحصول على معلومات قاعدة البيانات."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"ليست هناك أية جهات اتصال قابلة للتصدير. إذا كانت لديك جهات اتصال على هاتفك، فإن بعض موفري البيانات لا يسمحون بتصدير جهات الاتصال من الهاتف."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"لم يبدأ مؤلف vCard بشكل صحيح."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"تعذر التصدير"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"لم يتم تصدير بيانات جهة الاتصال.\nالسبب: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"جارٍ استيراد <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"تتعذر قراءة بيانات vCard."</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"تم إلغاء قراءة بيانات vCard"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"تم الانتهاء من استيراد ملف vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"تم إلغاء استيراد <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"سيتم استيراد <xliff:g id="FILENAME">%s</xliff:g> بعد قليل."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"سيتم استيراد الملف قريبًا."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"تم رفض طلب استيراد vCard. أعد المحاولة لاحقًا."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"سيتم تصدير <xliff:g id="FILENAME">%s</xliff:g> بعد قليل."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"تم رفض طلب تصدير vCard. أعد المحاولة لاحقًا."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"جهة اتصال"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"يجري تخزين ملفات vCard مؤقتًا على وحدة تخزين مؤقتة محلية. سيبدأ الاستيراد الفعلي قريبًا."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"تعذر استيراد vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"استلام ج اتص.NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"تصدير جهات الاتصال؟"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"تخزين مؤقت"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"استيراد <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"الإعدادات"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"مشاركة جهات الاتصال المرئية"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"استيراد/تصدير جهات اتصال"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"استيراد جهات الاتصال"</string>
+ <string name="share_error" msgid="948429331673358107">"لا يمكن مشاركة جهة الاتصال هذه."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"بحث"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"جهات الاتصال المعروضة"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"جهات الاتصال المعروضة"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"المفضلة"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"ليست هناك جهات اتصال."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"محو قائمة من يتصل بهم كثيرًا"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"تحديد شريحة SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"استيراد/تصدير"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"الأرقام المحظورة"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"عبر <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> عبر <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"محو البحث"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
index 2557079..7ec31a8 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az-rAZ/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Defolt ayarlayın"</string>
<string name="clear_default" msgid="7193185801596678067">"Defoltu təmizləyin"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Mətn kopyalandı"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Dəyişiklikləriniz kənarlaşdırılsın və redaktə sonlandırılsın?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Dəyişikliklər ləğv edilsin?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Ləğv edin"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Redaktəyə davam edin"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Ləğv edin"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Kontakt axtarın"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Kontaktları silin"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Haqqında"</string>
<string name="send_message" msgid="8938418965550543196">"Mesaj göndərin"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Şəxsi nüsxə yaradılır..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Dünən"</string>
<string name="tomorrow" msgid="6241969467795308581">"Sabah"</string>
<string name="today" msgid="8041090779381781781">"Bu gün"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Bu gün saat <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mesajlarım"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Siyahınızı sistemləşdirin"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Dublikatları və qrup kontaktlarını etiket vasitəsi ilə təmizləyin"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Mətn kopyalandı"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Panoya kopyalayın"</string>
+ <string name="call_custom" msgid="7756571794763171802">"<xliff:g id="CUSTOM">%s</xliff:g> zəng edin"</string>
+ <string name="call_home" msgid="1990519474420545392">"Evə zəng"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Mobil cihaza zəng edin"</string>
+ <string name="call_work" msgid="5328785911463744028">"İşə zəng"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"İş faksına zəng edin"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Ev faksına zəng edin"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Peycerə zəng edin"</string>
+ <string name="call_other" msgid="8563753966926932052">"Zəng edin"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Geriyə zəng edin"</string>
+ <string name="call_car" msgid="3280537320306436445">"Avtomobil zəngi"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Əsas şirkət zəngi"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"ISDN zəng edin"</string>
+ <string name="call_main" msgid="6082900571803441339">"Əsas zəng"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Faksa zəng edin"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Radioya zəng edin"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Teleksə zəng edin"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"TTY/TDD zəng edin"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"İş mobil telefonuna zəng edin"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"İş peycerinə zəng edin"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Zəng <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"MMS Zəng"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Mətn <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Ev mətni"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Mobil mətn"</string>
+ <string name="sms_work" msgid="2269624156655267740">"İş nömrəsinə mesaj"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"İş faksına mesaj göndərin"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Ev faksına mesaj göndərin"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Peycer nömrəsinə mesaj"</string>
+ <string name="sms_other" msgid="806127844607642331">"Mətn"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Geri zəng nömrəsinə mesaj"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Avtomobil nömrəsinə mesaj"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Əsas şirkət mətni"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"ISDN mətni"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Əsas mətn"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Faks nömrəsinə mesaj"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Radio mətni"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Teleks nömrəsinə mesaj"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"TTY/TDD nömrəsinə mesaj"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"İş mobil nömrəsinə mesaj"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"İş peyceri mətni"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Mətn <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"MMS nömrəsinə mesaj"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Tez-tez ünsiyyət qurulanlar silinsin?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Tez-tez ünsiyyət qurulanlar silinir..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Əlçatımlı"</string>
+ <string name="status_away" msgid="1838861100379804730">"Kənar"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Məşğul"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontaktlar"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Digər"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Kataloq"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Bütün kontaktlar"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Axtarılır..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g> ədəddən çox tapılıb."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Kontakt yoxdur"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> tapıldı</item>
+ <item quantity="one">1 nəfər tapıldı</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> üçün tez kontakt"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(ad yoxdur)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Tez-tez əlaqə saxlanan"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Kontakta baxın"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Telefon nömrələri olan bütün kontaktlar"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Güncəlləşmələri göstər"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Ad"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Nik"</string>
+ <string name="full_name" msgid="6602579550613988977">"Ad"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Ad prefiksi"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Atasının adı"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Ad suffiksi"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Fonetik ad"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetik atasının adı"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-poçt"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Ünvan"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Təşkilat"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Əlaqə"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Mətn mesajı"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Ünvan:"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Şirkət"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Başlıq"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Qeydlər"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Veb sayt"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Evə e-məktub yazın"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Mobil ünvana e-məktub"</string>
+ <string name="email_work" msgid="2807430017302722689">"İşə e-məktub yazın"</string>
+ <string name="email_other" msgid="3454004077967657109">"E-poçt"</string>
+ <string name="email_custom" msgid="7548003991586214105">"E-poçt <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-poçt"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Küçə"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO Box"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Qonşuluq"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Şəhər"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Dövlət"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Poçt indeksi"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Ölkə"</string>
+ <string name="map_home" msgid="1243547733423343982">"Ev ünvanına baxın"</string>
+ <string name="map_work" msgid="1360474076921878088">"İş ünvanına baxın"</string>
+ <string name="map_other" msgid="3817820803587012641">"Ünvana baxın"</string>
+ <string name="map_custom" msgid="6184363799976265281">"<xliff:g id="CUSTOM">%s</xliff:g> ünvanına baxın"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"AIM üzərindən çat"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Windows Live üzərindən söhbət"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Yahoo üzərindən çat"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Skype üzərindən çat"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"QQ üzərindən çat"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Google Söhbət üzərindən çat"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"ICQ üzərindən çat"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Jabber üzərindən çat"</string>
+ <string name="chat" msgid="9025361898797412245">"Çat"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"sil"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Ad sahələrini genişləndirin və ya yığcamlaşdırın"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Bütün kontaktlar"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Ulduzlu"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Fərdiləşdirin"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontakt"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Bütün digər kontaktlar"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Bütün kontaktlar"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Sinxronizasiya qrupunu silin"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Sinx qrup əlavə edin"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Daha çox qrup..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"\"<xliff:g id="GROUP">%s</xliff:g>\" qrupunun sinxronlaşmadan silinməsi istənilən qrupsuz kontaktı da sinxronlaşmadan siləcək."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Displey seçənəkləri yadda saxlanır..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Hazırdır"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Ləğv et"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM kartdan import edin"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> importu ləğv olunsun?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> eksportu ləğv edilsin?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Vizit kart importunu/eksportunu ləğv etmək mümkün olmadı"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Naməlum xəta."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" açmaq olmadı: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Eksporteri başlatmaq olmadı: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Eksport edilə bilən heç bir kontakt yoxdur."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Eksport zamanı xəta baş verdi: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Tələb olunan fayl adı çox uzundur (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O xəta"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Yetərincə yaddaş yoxdur. Fayl çox böyük ola bilər."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Gözlənilməyən səbəbə görə vizit kart təhlil edilə bilmədi."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Format dəstəklənmir."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Verilmiş vizit kartların meta məlumatları toplana bilmədi."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Bir və daha çox fayl import edilə bilməz (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> eksportu bitdi."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> eksportu ləğv edildi."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Kontakt datası eksport olunur"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Verilənlər bazası məlumatları əldə oluna bilmədi."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Eksport oluna bilən kontakt yoxdur. Əgər telefonunuzda kontakt varsa, bəzi data provayderləri kontaktların telefondan kənara eksport olunmasına icazə verməyə bilər."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Vizit kart tərtibçisi düzgün başlamadı."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Eksport edilə bilmədi"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Kontakt datası eksport edilmədi.\nSəbəb: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> import edilir"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Vizit kart datası oxuna bilmədi"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Vizit kart datasının oxunması ləğv edildi"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"<xliff:g id="FILENAME">%s</xliff:g> vizit kart importu qurtardı"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> importu ləğv edildi"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> tezliklə import olunacaq."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Bu fayl tezliklə import ediləcək."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Vizit kart import sorğusu rədd edildi. Yenidən cəhd edin."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> tezliklə eksport ediləcək."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Vizit kart eksport sorğusu rədd edildi. Daha sonra cəhd edin."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontakt"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Vizit kart yerli müvəqqəti yaddaşa keşlənir. Hazırkı import tezliklə başlayacaq."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Vizit kart import edilə bilmədi."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontakt NFC üzərindən alınıb"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Kontaktlar eksport olunsun?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Keşləndirilir"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"İmport edilir: <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Ayarlar"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Görünən kontaktları paylaşın"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Kontaktları import/eksport edin"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Kontaktların importu"</string>
+ <string name="share_error" msgid="948429331673358107">"Bu kontakt paylaşıla bilməz."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Axtar"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Göstərilməli kontaktlar"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Göstəriləsi kontaktlar"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritlər"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Kontakt yoxdur."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Müntəzəmləri təmizləyin"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM kart seçin"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"İmport/eksport"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Bloklanmış nömrələr"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g> vasitəsilə"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="SOURCE">%2$s</xliff:g> vasitəsilə <xliff:g id="DATE">%1$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Axtarışı təmizləyin"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 6b0cb8d..7c9b856 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Задаване като стандартна настройка"</string>
<string name="clear_default" msgid="7193185801596678067">"Изчистване на стандартната настройка"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Текстът бе копиран"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Искате ли да отхвърлите направените от вас промени и да излезете от редактирането?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Да се отхвърлят ли промените?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Отхвърляне"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Продължаване с редактирането"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Отказ"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Търсене в контактите"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Премахване на контакти"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Информация"</string>
<string name="send_message" msgid="8938418965550543196">"Изпращане на съобщение"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Създава се лично копие..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Вчера"</string>
<string name="tomorrow" msgid="6241969467795308581">"Утре"</string>
<string name="today" msgid="8041090779381781781">"Днес"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Днес от <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Съобщения"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Организирайте списъка си"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Разчистете дубликатите и групирайте контактите по етикет"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Текстът бе копиран"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Копиране в буфера"</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="8563753966926932052">"Обаждане"</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="5745314124619636674">"Обаждане на факс"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Изпращане на SMS на <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Изпращaне на SMS на домашен"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Изпращaне на 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="806127844607642331">"Текст"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Изпращане на SMS на отговорилия"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Изпращане на SMS на кола"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Изпращaне на SMS на основен служебен"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Изпращaне на SMS на ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Изпращане на SMS на основен"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Изпращане на 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">"Изпращане на SMS на TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Изпращане на SMS на служебен мобилен"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Изпращaне на SMS на служебен пейджър"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Изпращане на SMS на <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Изпращане на SMS на MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Да се изчистят ли често търсените?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Често търсените се изчистват…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Налице"</string>
+ <string name="status_away" msgid="1838861100379804730">"Отсъства"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Зает/а"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Контакти"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Други"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Директория"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Всички контакти"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Търси се..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Намерени са повече от <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Няма контакти"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> намерени</item>
+ <item quantity="one">1 намерен</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Бърз контакт за <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Няма име)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Често търсени"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Преглед на контакта"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Всички контакти с телефонни номера"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Актуализации"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Име"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Псевдоним"</string>
+ <string name="full_name" msgid="6602579550613988977">"Име"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Име, както се произнася"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Презиме, както се произнася"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Телефон"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Имейл"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Адрес"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Незабавни съобщения"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Организация"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Отношение"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Текстово съобщение"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Адрес"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Фирма"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Заглавие"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Бележки"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Уебсайт"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"Изпращане на имейл"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Изпращане на имейл до <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Изпращане на имейл"</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="map_home" msgid="1243547733423343982">"Преглед на домашен адрес"</string>
+ <string name="map_work" msgid="1360474076921878088">"Преглед на служебен адрес"</string>
+ <string name="map_other" msgid="3817820803587012641">"Преглед на адрес"</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="description_minus_button" msgid="6908099247930477551">"изтриване"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Разгъване или свиване на полетата за името"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Всички контакти"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Със звезда"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Персонализиране"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Контакт"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Всички други контакти"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Всички контакти"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Ако синхронизирането на „<xliff:g id="GROUP">%s</xliff:g>“ спре, то ще спре и за негрупираните контакти."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Опциите за показване се запазват..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Готово"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Отказ"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Импортиране от SIM карта"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Да се анулира ли импортирането на <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Да се анулира ли експортирането на <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Импорт./експорт. не можа да се анулира"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Неизвестна грешка."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"„<xliff:g id="FILE_NAME">%s</xliff:g>“ не можа да се отвори: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Експортирането не можа да започне: „<xliff:g id="EXACT_REASON">%s</xliff:g>“."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Няма контакт, позволяващ експортиране."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Възникна грешка при експортирането: „<xliff:g id="EXACT_REASON">%s</xliff:g>“."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Изисканото име на файла е твърде дълго („<xliff:g id="FILENAME">%s</xliff:g>“)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O грешка"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Няма достатъчно памет. Файлът може да е твърде голям."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"vCard не можа да бъде анализирана по неочаквана причина."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Форматът не се поддържа."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Метаинформацията от даден/и vCard файл/ове не можа да бъде събрана."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Един или повече файла не можаха да бъдат импортирани (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Експортирането на <xliff:g id="FILENAME">%s</xliff:g> завърши."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Експортирането на <xliff:g id="FILENAME">%s</xliff:g> е анулирано."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Експортиране на данни за контакти"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Информацията за базата от данни не можа да бъде получена."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Няма контакти, позволяващи експортиране. Ако в телефона си имате контакти, е възможно някои доставчици на данни да не позволяват експортирането им извън него."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Създателят на vCard не се стартира правилно."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Не се експортира"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Данните за контакта не бяха експортирани.\nПричина: „<xliff:g id="FAIL_REASON">%s</xliff:g>“"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> се импортира"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Данните не можаха да бъдат прочетени"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Четенето на данни от vCard е анулирано"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Импортирането на vCard <xliff:g id="FILENAME">%s</xliff:g> завърши"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Импортирането на <xliff:g id="FILENAME">%s</xliff:g> е анулирано"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> ще се импортира скоро."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Файлът ще се импортира скоро."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Заявката за импортиране на vCard бе отхвърлена. Опитайте отново по-късно."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> ще се експортира скоро."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Заявката за експортиране на vCard бе отхвърлена. Опитайте отново по-късно."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"контакт"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard се кешира/т във временно локално хранилище. Самото импортиране ще започне скоро."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard не можа да бъде импортирана."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Контакт: Получ. чрез NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Да се експортират ли контактите?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Кешира се"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Импортира се <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Настройки"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Споделяне на видимите контакти"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Импортиране/Експортиране на контакти"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Импортиране на контактите"</string>
+ <string name="share_error" msgid="948429331673358107">"Този контакт не може да бъде споделен."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Търсене"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Контакти за показване"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Контакти за показване"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Любими"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Няма контакти."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Изчистване на често търсените"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Избиране на SIM карта"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Импортиране/Експортиране"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Блокирани номера"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"чрез <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> чрез <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Изчистване на търсенето"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index 21ddf31..31822d3 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"ডিফল্ট সেট করুন"</string>
<string name="clear_default" msgid="7193185801596678067">"ডিফল্ট সাফ করুন"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"পাঠ্য অনুলিপি হয়েছে"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"আপনার পরিবর্তনগুলি বাতিল করতে এবং সম্পাদনা থেকে প্রস্থান করতে চান?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"পরিবর্তনগুলি বাতিল করবেন?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"বাতিল করুন"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"সম্পাদনা করা চালিয়ে যান"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"বাতিল করুন"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"পরিচিতিগুলি খুঁজুন"</string>
<string name="title_edit_group" msgid="8602752287270586734">"পরিচিতিগুলি সরান"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"সম্পর্কে"</string>
<string name="send_message" msgid="8938418965550543196">"বার্তা পাঠান"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"একটি ব্যক্তিগত অনুলিপি তৈরি করা হচ্ছে…"</string>
- <string name="yesterday" msgid="6840858548955018569">"গতকাল"</string>
<string name="tomorrow" msgid="6241969467795308581">"আগামীকাল"</string>
<string name="today" msgid="8041090779381781781">"আজ"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"আজ <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"বার্তাগুলি"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"আপনার তালিকা সংগঠিত করুন"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"সদৃশগুলিকে সাফ এবং লেবেল অনুযায়ী পরিচিতিগুলিকে গোষ্ঠীবদ্ধ করুন"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"পাঠ্য অনুলিপি হয়েছে"</string>
+ <string name="copy_text" msgid="3257145021583508761">"ক্লিপবোর্ডে কপি করুন"</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="8563753966926932052">"কল করুন"</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="5745314124619636674">"ফ্যাক্স নম্বরে কল করুন"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"পাঠ্য"</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="3888842199855843152">"ফ্যাক্স নম্বরে পাঠ্য বার্তা পাঠান"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"ঘন ঘন যোগাযোগ করা হয়েছে এমন পরিচিতিগুলিকে সাফ করবেন?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"ঘন ঘন যোগাযোগ করা পরিচিতিগুলিকে সাফ করা হচ্ছে…"</string>
+ <string name="status_available" msgid="5586870015822828392">"উপলব্ধ"</string>
+ <string name="status_away" msgid="1838861100379804730">"অন্যত্র"</string>
+ <string name="status_busy" msgid="9147992455450257136">"ব্যস্ত"</string>
+ <string name="contactsList" msgid="8661624236494819731">"পরিচিতিগুলি"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"অন্যান্য"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"ডিরেক্টরি"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"সকল পরিচিতি"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"অনুসন্ধান করছে..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g>টির থেকে বেশি খুঁজে পাওয়া গিয়েছে৷"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"কোনো পরিচিতি নেই"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g>টি খুঁজে পাওয়া গেছে</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g>টি খুঁজে পাওয়া গেছে</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> এর জন্য দ্রুত পরিচিতি"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(কোনও নাম নেই)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"ঘন ঘন যোগাযোগ করা হয়েছে"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"পরিচিতি দেখুন"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"ফোন নম্বর সহ সমস্ত পরিচিতি"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"আপডেটগুলি দেখুন"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"নাম"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"ডাকনাম"</string>
+ <string name="full_name" msgid="6602579550613988977">"নাম"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"উচ্চারণগত নাম"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"উচ্চারণগত মাঝের নাম"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"ফোন"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"ইমেল করুন"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"ঠিকানা"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"সংগঠন"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"সম্পর্ক"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"পাঠ্য বার্তা"</string>
+ <string name="postal_address" msgid="8765560217149624536">"ঠিকানা"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"কোম্পানি"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"শীর্ষক"</string>
+ <string name="label_notes" msgid="8337354953278341042">"নোটগুলি"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"ওয়েবসাইট"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"ইমেল করুন"</string>
+ <string name="email_custom" msgid="7548003991586214105">"<xliff:g id="CUSTOM">%s</xliff:g> এ ইমেল করুন"</string>
+ <string name="email" msgid="5668400997660065897">"ইমেল করুন"</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="map_home" msgid="1243547733423343982">"বাড়ির ঠিকানা দেখুন"</string>
+ <string name="map_work" msgid="1360474076921878088">"কর্মক্ষেত্রের ঠিকানা দেখুন"</string>
+ <string name="map_other" msgid="3817820803587012641">"ঠিকানা দেখুন"</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="description_minus_button" msgid="6908099247930477551">"মুছুন"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"নামের ক্ষেত্রটিকে প্রসারিত বা সঙ্কুচিত করুন"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"সকল পরিচিতি"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"তারকাচিহ্নিত"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"নিজের সুবিধামতো করুন"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"পরিচিতি"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"অন্যান্য সকল পরিচিতি"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"সকল পরিচিতি"</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_warn_remove_ungrouped" msgid="8872290721676651414">"সমন্বয় থেকে \"<xliff:g id="GROUP">%s</xliff:g>\" সরানো হলে তা সমন্বয় থেকে যেকোনো অগোষ্ঠীবদ্ধ পরিচিতিগুলিকেও সরাবে৷"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"প্রদর্শনের বিকল্পগুলি সংরক্ষণ করা হচ্ছে..."</string>
+ <string name="menu_done" msgid="796017761764190697">"সম্পন্ন হয়েছে"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"বাতিল করুন"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"সিম কার্ড থেকে আমদানি করুন"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> এর আমদানি বাতিল করবেন?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> এর রপ্তানি বাতিল করবেন?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard এর আমদানি/রপ্তানি বাতিল করা যায়নি"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"অজানা ত্রুটি৷"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" খোলা যায়নি: <xliff:g id="EXACT_REASON">%s</xliff:g>৷"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"রপ্তানিকারক শুরু করা যায়নি: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"৷"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"রফতানিযোগ্য কোনো পরিচিতি নেই৷"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"রপ্তানির সময় একটি ত্রুটি ঘটেছে: \" <xliff:g id="EXACT_REASON">%s</xliff:g> \"৷"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"প্রয়োজনীয় ফাইলের নামটি (\"<xliff:g id="FILENAME">%s</xliff:g>\") অত্যন্ত দীর্ঘ৷"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O ত্রুটি"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"যথেষ্ট মেমরি নেই৷ ফাইলটি খুব বড় হতে পারে৷"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"একটি অপ্রত্যাশিত কারণে vCard পার্জ করা যায়নি৷"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"এই ফর্ম্যাটটি সমর্থিত নয়৷"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"প্রদত্ত vCard ফাইলের(গুলির) মেটা তথ্য সংগ্রহ করা যায়নি৷"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"একটি বা একাধিক (%s) ফাইল আমদানি করা যাবে না৷"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> রপ্তানি করা সম্পন্ন হয়েছে৷"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> রপ্তানি করা বাতিল হয়েছে৷"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"পরিচিতির তথ্য রপ্তানি করা হচ্ছে"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"ডেটাবেসের তথ্য পাওয়া যায়নি৷"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"এখানে রপ্তানিযোগ্য কোনো পরিচিতি নেই৷ আপনার ফোনে পরিচিতি থাকলে, কিছু ডেটা সরবরাহকারী আপনার ফোন থেকে সেই পরিচিতিগুলিকে রপ্তানি করা মঞ্জুর নাও করতে পারে৷"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard কম্পোজার সঠিকভাবে শুরু করা হয়নি৷"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"রপ্তানি করা যায়নি"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"পরিচিতির তথ্য রপ্তানি করা যায়নি৷\nকারণ: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> আমদানি করা হচ্ছে"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard ডেটা পড়া যায়নি"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard ডেটা পড়া বাতিল করা হয়েছে"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g> আমদানি করা সমাপ্ত হয়েছে"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> আমদানি করা বাতিল করা হয়েছে"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> শীঘ্রই আমদানি করা হবে৷"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"ফাইলটি শীঘ্রই আমদানি করা হবে৷"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard আমদানি করার অনুরোধ প্রত্যাখ্যাত হয়েছে৷ পরে আবার চেষ্টা করুন৷"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> শীঘ্রই রপ্তানি করা হবে৷"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard রপ্তানি করার অনুরোধ প্রত্যাখ্যাত হয়েছে৷ পরে আবার চেষ্টা করুন৷"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"পরিচিতি"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"স্থানীয় অস্থায়ী সংগ্রহস্থলে vCard(গুলি)কে ক্যাশ করা হচ্ছে৷ প্রকৃত আমদানি শীঘ্রই শুরু হবে৷"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard আমদানি করতে পারা যায় নি৷"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC এর মাধ্যমে পরিচিতি প্রাপ্ত হয়েছে"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"পরিচিতিগুলি রপ্তানি করবেন?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"ক্যাশ করা হচ্ছে"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"আমদানি করা হচ্ছে, <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"সেটিংস"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"দৃশ্যমান পরিচিতিগুলিকে শেয়ার করুন"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"পরিচিতিগুলি আমদানি/রপ্তানি করুন"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"পরিচিতিগুলি আমদানি করুন"</string>
+ <string name="share_error" msgid="948429331673358107">"এই পরিচিতিটিকে শেয়ার করা যাবে না৷"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"অনুসন্ধান"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"দেখানোর জন্য পরিচিতিগুলি"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"দেখানোর জন্য পরিচিতিগুলি"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"পছন্দসইগুলি"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"কোনো পরিচিতি নেই৷"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"পুনরাবৃত্তি সাফ করুন"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"সিম কার্ড নির্বাচন করুন"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"আমদানি/রপ্তানি"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"অবরোধ করা নম্বরগুলি"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g> এর মাধ্যমে"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="SOURCE">%2$s</xliff:g> এর মাধ্যমে <xliff:g id="DATE">%1$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"অনুসন্ধান সাফ করুন"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 95dff95..1844a0e 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Predeterminat"</string>
<string name="clear_default" msgid="7193185801596678067">"Esborra els valors predeterminats"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Text copiat"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Vols descartar els canvis i sortir del mode d\'edició?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Vols descartar els canvis?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Descarta"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Continua editant"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Cancel·la"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Cerca als contactes"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Suprimeix els contactes"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Quant a"</string>
<string name="send_message" msgid="8938418965550543196">"Envia un missatge"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"S\'està creant una còpia personal..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Ahir"</string>
<string name="tomorrow" msgid="6241969467795308581">"Demà"</string>
<string name="today" msgid="8041090779381781781">"Avui"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Avui a les <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Missatges"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organitza la llista"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Fes neteja dels duplicats i agrupa els contactes per etiqueta"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Text copiat"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copia al porta-retalls"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Truca a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Truca a casa"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Truca al mòbil"</string>
+ <string name="call_work" msgid="5328785911463744028">"Truca a la feina"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Truca al fax de la feina"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Truca al fax particular"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Truca al cercapersones"</string>
+ <string name="call_other" msgid="8563753966926932052">"Truca a"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Truca al número de crida de retorn"</string>
+ <string name="call_car" msgid="3280537320306436445">"Truca al cotxe"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Truca el telèfon principal de l\'empresa"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Truca a l\'XDSI"</string>
+ <string name="call_main" msgid="6082900571803441339">"Truca al telèfon principal"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Truca al fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Truca a la ràdio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Truca al tèlex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Truca a TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Truca al mòbil de la feina"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Truca al cercapersones de la feina"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Truca a <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Truca al número MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Envia un SMS a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Envia un SMS al número particular"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Envia un SMS al mòbil"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Envia un SMS a la feina"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Envia un SMS al fax de la feina"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Envia un SMS al fax particular"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Envia un SMS al cercapersones"</string>
+ <string name="sms_other" msgid="806127844607642331">"Envia un SMS"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Envia un SMS a la crida de retorn"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Envia un SMS al cotxe"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Envia un SMS al telèfon principal de l\'empresa"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Envia un SMS a l\'XDSI"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Envia un SMS al telèfon principal"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Envia un SMS al fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Envia un SMS a la ràdio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Envia un SMS al tèlex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Envia un SMS al TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Envia un SMS al telèfon de la feina"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Envia un SMS al cercapersones de la feina"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Envia un SMS a <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Envia un MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Vols esborrar contac. més freqüents?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"S\'està esb. cont. més freqüents..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Disponible"</string>
+ <string name="status_away" msgid="1838861100379804730">"Absent"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Ocupat"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contactes"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Altres"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">" Directori"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Tots els contactes"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"S\'està cercant..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Se n\'han trobat més de <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"No hi ha cap contacte"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> contactes</item>
+ <item quantity="one">1 contacte</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Contacte ràpid per a <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Sense nom)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Contactats sovint"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Mostra el contacte"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Tots els contactes amb números de telèfon"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Mostra actualitzac."</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nom"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Àlies"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nom"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Prefix del nom"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Segon nom"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Sufix del nom"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nom fonètic"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Primer cognom fonètic"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telèfon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Correu electrònic"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adreça"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Xat"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organització"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relació"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Missatge de text"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adreça"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Títol"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notes"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Lloc web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Envia un correu electrònic a l\'adreça particular"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Envia un correu electrònic al mòbil"</string>
+ <string name="email_work" msgid="2807430017302722689">"Envia un correu electrònic a la feina"</string>
+ <string name="email_other" msgid="3454004077967657109">"Envia un correu electrònic"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Envia un correu electrònic a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Envia un correu electrònic"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Carrer"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Apartat postal"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Barri"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Ciutat"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Estat"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Codi postal"</string>
+ <string name="postal_country" msgid="7638264508416368690">"País"</string>
+ <string name="map_home" msgid="1243547733423343982">"Visualitza l\'adreça particular"</string>
+ <string name="map_work" msgid="1360474076921878088">"Visualitza l\'adreça de la feina"</string>
+ <string name="map_other" msgid="3817820803587012641">"Visualitza l\'adreça"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Visualitza l\'adreça <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Xateja amb AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Xateja amb Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Xateja amb Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Xateja amb Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Xateja amb QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Xateja amb Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Xateja amb ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Xateja amb Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Fes un xat"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"suprimeix"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Amplia o redueix els camps de nom"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Tots els contactes"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Destacats"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personalitza"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contacte"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"La resta de contactes"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Tots els contactes"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Elimina el grup de sincronització"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Afegeix un grup de sincronització"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Més grups..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Si s\'elimina \"<xliff:g id="GROUP">%s</xliff:g>\" de la sincronització, també se n\'eliminaran els contactes no agrupats."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"S\'estan desant les opcions de visualització..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Fet"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Cancel·la"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importa des de la targeta SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Vols cancel·lar la importació de: <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Vols cancel·lar l\'exportació de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"No es pot cancel·lar la imp./exp. vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"S\'ha produït un error desconegut."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"No s\'ha pogut obrir \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"No s\'ha pogut iniciar l\'exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"No hi ha cap contacte que es pugui exportar."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"S\'ha produït un error durant l\'exportació: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"El nom de fitxer obligatori és massa llarg (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Error d\'E/S"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"No hi ha prou memòria. És possible que el fitxer sigui massa gran."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"No s\'ha pogut analitzar la vCard a causa d\'un motiu inesperat."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"No s\'admet aquest format."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"No s\'ha pogut recopilar metainformació dels fitxers de la vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"No s\'ha pogut importar un dels fitxers com a mínim (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Exportació de <xliff:g id="FILENAME">%s</xliff:g> finalitzada."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"S\'ha cancel·lat l\'exportació de: <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"S\'estan exportant les dades de contacte"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"No s\'ha pogut obtenir informació de la base de dades."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"No hi ha cap contacte que es pugui exportar. Si en tens algun al telèfon, és possible que hi hagi proveïdors de dades que no permetin que els contactes s\'exportin des del telèfon."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"No s\'ha iniciat correctament el creador de vCard."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Error en exportar"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"No s\'han exportat les dades de contacte.\nMotiu: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"S\'està important <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"No s\'han pogut llegir les dades de vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"S\'ha cancel·lat la lectura de dades de vCard"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Importació de vCard <xliff:g id="FILENAME">%s</xliff:g> finalitzada"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"S\'ha cancel·lat la importació de: <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> s\'importarà d\'aquí a una estona."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"D\'aquí a poc s\'importarà el fitxer."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"S\'ha rebutjat la sol·licitud per importar vCard. Torna-ho a provar més tard."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> s\'exportarà en breu."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"S\'ha rebutjat la sol·licitud per exportar vCard. Torna-ho a provar més tard."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contacte"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"S\'estan desant els vCard a l\'emmagatzematge temporal local. La importació real començarà aviat."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"No s\'ha pogut importar la vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contac. reb. NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exportació contactes"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Desament a la memòria cau"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"S\'està important <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Configuració"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Comparteix els contactes visibles"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importa/exporta contactes"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importació de contactes"</string>
+ <string name="share_error" msgid="948429331673358107">"No es pot compartir aquest contacte."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Cerca"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contactes per mostrar"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contactes per mostrar"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Preferits"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"No hi ha cap contacte."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Esborra els freqüents"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Selecciona una targeta SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importa/exporta"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Números bloquejats"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"mitjançant <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> mitjançant <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Esborra la cerca"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index de11f48..ffd612c 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -246,9 +246,9 @@
<string name="set_default" msgid="4417505153468300351">"Výchozí nastavení"</string>
<string name="clear_default" msgid="7193185801596678067">"Vymazat výchozí nastavení"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Text zkopírován"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Zahodit změny a ukončit úpravy?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Zahodit změny?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Zrušit"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Pokračovat v úpravách"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Zrušit"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Vyhledejte kontakty"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Odebrat kontakty"</string>
@@ -273,7 +273,6 @@
<string name="about_card_title" msgid="2920942314212825637">"O kartě"</string>
<string name="send_message" msgid="8938418965550543196">"Odeslat zprávu"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Vytváření osobní kopie..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Včera"</string>
<string name="tomorrow" msgid="6241969467795308581">"Zítra"</string>
<string name="today" msgid="8041090779381781781">"Dnes"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Dnes v <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -364,4 +363,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Zprávy"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Udělejte si v kontaktech pořádek"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Zbavte se duplicit a seskupte kontakty pod štítky"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Text zkopírován"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Zkopírovat do schránky"</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="8563753966926932052">"Volat"</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="5745314124619636674">"Volat fax"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"SMS"</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="3888842199855843152">"SMS na fax"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Vymazat často kontaktované osoby?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Mazání často kontaktovaných osob..."</string>
+ <string name="status_available" msgid="5586870015822828392">"K dispozici"</string>
+ <string name="status_away" msgid="1838861100379804730">"Pryč"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Nemám čas"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontakty"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Ostatní"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Adresář"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Všechny kontakty"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Vyhledávání..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Nalezeno více kontaktů než <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Žádné kontakty"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="few">Nalezeno: <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="many">Nalezeno: <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="other">Nalezeno: <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="one">Nalezeno: 1</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Rychlý kontakt <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Žádné jméno)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Často používané kontakty"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Zobrazit kontakt"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Všechny kontakty s telefonními čísly"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Zobrazit aktualizace"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Jméno"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Přezdívka"</string>
+ <string name="full_name" msgid="6602579550613988977">"Jméno"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Jméno (foneticky)"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Druhé jméno (foneticky)"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mail"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adresa"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Chat"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizace"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Vztah"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Textová zpráva"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adresa"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Společnost"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Název"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Poznámky"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Webové stránky"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"E-mail"</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="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="map_home" msgid="1243547733423343982">"Zobrazit adresu domů"</string>
+ <string name="map_work" msgid="1360474076921878088">"Zobrazit pracovní adresu"</string>
+ <string name="map_other" msgid="3817820803587012641">"Zobrazit adresu"</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="description_minus_button" msgid="6908099247930477551">"smazat"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Rozbalit nebo sbalit pole jména"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Všechny kontakty"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Označené hvězdičkou"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Přizpůsobit"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontakt"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Všechny ostatní kontakty"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Všechny kontakty"</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_warn_remove_ungrouped" msgid="8872290721676651414">"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="savingDisplayGroups" msgid="2133152192716475939">"Ukládání možností zobrazení…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Hotovo"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Zrušit"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importovat ze SIM karty"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Zrušit import souboru <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Zrušit export souboru <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Import/export vizitky vCard nelze zrušit"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Neznámá chyba."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Soubor <xliff:g id="FILE_NAME">%s</xliff:g> nelze otevřít: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Nelze spustit nástroj pro export: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Žádný kontakt nelze exportovat."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Při exportu došlo k chybě: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Požadovaný název souboru (<xliff:g id="FILENAME">%s</xliff:g>) je příliš dlouhý."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Chyba I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Není k dispozici dostatek paměti. Soubor může být příliš velký."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Analýza souboru vCard se z neočekávaných důvodů nezdařila."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Formát není podporován."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Informace o metadatech daných souborů vCard se nepodařilo shromáždit."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Jeden nebo více souborů se nepodařilo importovat (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Export souboru <xliff:g id="FILENAME">%s</xliff:g> byl dokončen."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Export souboru <xliff:g id="FILENAME">%s</xliff:g> byl zrušen."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Export dat kontaktů"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Nepodařilo se získat informace o databázi."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Nelze exportovat žádné kontakty. Pokud máte v telefonu skutečně uložené kontakty, je možné, že některý poskytovatel datových služeb zakázal jejich export mimo telefon."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Editor souboru vCard nebyl správně spuštěn."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Export se nezdařil"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Data kontaktů nebyla exportována.\nDůvod: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Probíhá import: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Nepodařilo se přečíst údaje vizitky vCard."</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Čtení dat souboru vCard bylo zrušeno"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Import souboru vCard byl dokončen <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Import souboru <xliff:g id="FILENAME">%s</xliff:g> byl zrušen."</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Soubor <xliff:g id="FILENAME">%s</xliff:g> bude za okamžik importován."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Soubor bude zakrátko importován."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Požadavek na import souborů vCard byl zamítnut. Zkuste to prosím později."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Soubor <xliff:g id="FILENAME">%s</xliff:g> bude za okamžik exportován."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Požadavek na export souborů vCard byl zamítnut. Zkuste to prosím později."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontakt"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Načítání souboru vCard do mezipaměti místního dočasného úložiště. Vlastní import bude zahájen v krátké době."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Soubor vCard se nepodařilo importovat."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontakt přijatý přes NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exportovat kontakty?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Ukládání do mezipaměti"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Probíhá import: <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Nastavení"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Sdílet viditelné kontakty"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importovat nebo exportovat kontakty"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importovat kontakty"</string>
+ <string name="share_error" msgid="948429331673358107">"Tento kontakt nelze sdílet."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Hledat"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kontakty k zobrazení"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kontakty k zobrazení"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Oblíbené"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Žádné kontakty."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Vymazat často kontaktované os."</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Vybrat SIM kartu"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importovat/Exportovat"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blokovaná čísla"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"pomocí služby <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> prostřednictvím služby <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Vymazat vyhledávání"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 6a02ce4..8d26d42 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Indstil standard"</string>
<string name="clear_default" msgid="7193185801596678067">"Ryd standarder"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Kopieret tekst"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Vil du kassere ændringerne og afslutte redigering?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Vil du kassere ændringerne?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Kassér"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Fortsæt redigering"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Annuller"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Søg i kontaktpersoner"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Fjern kontaktpersoner"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Om"</string>
<string name="send_message" msgid="8938418965550543196">"Send besked"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Opretter en privat kopi..."</string>
- <string name="yesterday" msgid="6840858548955018569">"I går"</string>
<string name="tomorrow" msgid="6241969467795308581">"I morgen"</string>
<string name="today" msgid="8041090779381781781">"I dag"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"I dag kl. <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Meddelelser"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organiser din liste"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Fjern dubletter, og gruppér kontaktpersoner efter etiket"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Kopieret tekst"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopier til udklipsholder"</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="8563753966926932052">"Opkald"</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="5745314124619636674">"Ring til 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 på 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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Send sms"</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="3888842199855843152">"Send sms til 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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Vil du rydde de ofte kontaktede?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Rydder ofte kontaktede personer…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Tilgængelig"</string>
+ <string name="status_away" msgid="1838861100379804730">"Ikke til stede"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Optaget"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontakter"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Andre"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Indeks"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Alle kontaktpersoner"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Søger..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Der er fundet mere end <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Ingen kontaktpersoner"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one">Der blev fundet <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="other">Der blev fundet <xliff:g id="COUNT">%d</xliff:g></item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Hurtigkontakt for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Intet navn)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Jævnligt kontaktet"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Vis kontaktperson"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Alle kontaktpersoner med telefonnumre"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Se opdateringer"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Navn"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Kaldenavn"</string>
+ <string name="full_name" msgid="6602579550613988977">"Navn"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Fonetisk navn"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetisk mellemnavn"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mail"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adresse"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Forhold"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Sms"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adresse"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Virksomhed"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titel"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Noter"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"E-mail"</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="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">"Stat"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postnummer"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Land"</string>
+ <string name="map_home" msgid="1243547733423343982">"Vis hjemmeadresse"</string>
+ <string name="map_work" msgid="1360474076921878088">"Vis arbejdsadresse"</string>
+ <string name="map_other" msgid="3817820803587012641">"Vis 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="description_minus_button" msgid="6908099247930477551">"slet"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Udvid eller skjul navnefelter"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Alle kontaktpersoner"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Stjernemarkerede"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Tilpas"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontaktperson"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Alle andre kontaktpersoner"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Alle kontaktpersoner"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Hvis du fjerner \"<xliff:g id="GROUP">%s</xliff:g>\" fra synkroniseringen, fjernes alle ugrupperede kontaktpersoner fra synkroniseringen."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Gemmer indstillinger for visning…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Gem"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Annuller"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importer fra SIM-kort"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Vil du annullere import af <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Vil du annullere eksport af <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Import/eksport af vCard kunne ikke annulleres"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Ukendt fejl."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" kunne ikke åbnes: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Eksportfunktionen kunne ikke startes: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Der er ingen kontaktpersoner, der kan eksporteres."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Der opstod en fejl under eksporten: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Det krævede filnavn er for langt (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O-fejl"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Ikke nok hukommelse. Filen kan være for stor."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"vCard kunne ikke parses af uventede årsager."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Formatet understøttes ikke."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Metaoplysninger om de angivne vCard-filer kunne ikke hentes."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"En eller flere filer kunne ikke importeres (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> er eksporteret."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Eksport af <xliff:g id="FILENAME">%s</xliff:g> er annulleret."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Eksporterer kontaktdata"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Databaseoplysningerne kunne ikke hentes."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Der er ingen kontaktpersoner, der kan eksporteres. Hvis du har kontaktpersoner på din telefon, kan nogle dataudbydere ikke tillade, at kontaktpersonerne eksporteres fra telefonen."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Oprettelsen af vCard startede ikke korrekt."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Eksport ikke mulig"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Kontaktpersondataene blev ikke eksporteret.\nÅrsag: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importerer <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Dataene på dette vCard kunne ikke læses"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Læsning af vCard-data blev annulleret"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Import af vCard afsluttet <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Import af <xliff:g id="FILENAME">%s</xliff:g> blev annulleret"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> importeres om et øjeblik."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Filen importeres inden længe."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Anmodningen om import af vCard blev afvist. Prøv igen senere."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> eksporteres om et øjeblik."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Anmodningen om eksport af vCard blev afvist. Prøv igen senere."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontakt"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Cachelagrer vCard(s) til lokalt midlertidigt lager. Den egentlige import starter snart."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard kunne ikke importeres."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontakt via NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Eksporter kontakter?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Cachelagrer"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importerer <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Indstillinger"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Del synlige kontaktpersoner"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Import/eksport kontakter"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importer kontaktpersoner"</string>
+ <string name="share_error" msgid="948429331673358107">"Denne kontaktperson kan ikke deles."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Søg"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kontakter, der skal vises"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Viste kontaktpersoner"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favorit"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Ingen kontaktpersoner."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Ryd hyppige"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Vælg SIM-kort"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importer og eksporter"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blokerede telefonnumre"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Ryd søgning"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index f2566fb..89bdeac 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Als Standard festlegen"</string>
<string name="clear_default" msgid="7193185801596678067">"Als Standard löschen"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Text kopiert"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Möchtest du die Änderungen verwerfen und den Bearbeitungsmodus beenden?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Änderungen verwerfen?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Verwerfen"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Bearbeitung fortsetzen"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Abbrechen"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Kontakte suchen"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Kontakte entfernen"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Info"</string>
<string name="send_message" msgid="8938418965550543196">"Nachricht senden"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Persönliche Kopie wird erstellt..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Gestern"</string>
<string name="tomorrow" msgid="6241969467795308581">"Morgen"</string>
<string name="today" msgid="8041090779381781781">"Heute"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Heute um <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Nachrichten"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Liste organisieren"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Duplikate bereinigen und Kontakte nach Label gruppieren"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Text kopiert"</string>
+ <string name="copy_text" msgid="3257145021583508761">"In Zwischenablage kopieren"</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 (geschäftl.)"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Fax (geschäftlich) anrufen"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Fax (privat) anrufen"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Anruf (Pager)"</string>
+ <string name="call_other" msgid="8563753966926932052">"Anruf"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Rückrufnummer anrufen"</string>
+ <string name="call_car" msgid="3280537320306436445">"Auto anrufen"</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="5745314124619636674">"Anruf an Fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Anruf (Funktelefon)"</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">"Anruf Handy (geschäftl.)"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Anruf Pager (geschäftl.)"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Text <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"SMS (privat)"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Text (mobil)"</string>
+ <string name="sms_work" msgid="2269624156655267740">"SMS (geschäftl.)"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"SMS an Fax (geschäftl.)"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"SMS an Fax (privat)"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Text-Pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"SMS an"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"SMS 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">"SMS an ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"SMS an Hauptnummer"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"SMS an Fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Text (Funktelefon)"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"SMS an Telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"SMS an TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"SMS an Handy (geschäftl.)"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"SMS an Pager (geschäftl.)"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"SMS an <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Text (MMS)"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Liste \"Häufig kontaktiert\" löschen?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"\"Häufig kontaktiert\" wird gelöscht…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Verfügbar"</string>
+ <string name="status_away" msgid="1838861100379804730">"Abwesend"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Beschäftigt"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontakte"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Sonstige"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Verzeichnis"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Alle Kontakte"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Suche..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Mehr als <xliff:g id="COUNT">%d</xliff:g> gefunden"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Keine Kontakte"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> Kontakte gefunden</item>
+ <item quantity="one">1 Kontakt gefunden</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Schnellkontakt für <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Kein Name)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Häufig kontaktiert"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Kontakt anzeigen"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Alle Kontakte mit Telefonnummern"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Updates anzeigen"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Name"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Alias"</string>
+ <string name="full_name" msgid="6602579550613988977">"Name"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Phonetischer Name"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Phonetischer zweiter Vorname"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-Mail"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adresse"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Chat"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Firma/Organisation"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Beziehung"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"SMS"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adresse"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Unternehmen"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titel"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notizen"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"E-Mail (privat)"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-Mail (mobil)"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-Mail (geschäftl.)"</string>
+ <string name="email_other" msgid="3454004077967657109">"E-Mail an"</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="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">"Bundesland"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postleitzahl"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Land"</string>
+ <string name="map_home" msgid="1243547733423343982">"Privatadresse anzeigen"</string>
+ <string name="map_work" msgid="1360474076921878088">"Geschäftsadresse anzeigen"</string>
+ <string name="map_other" msgid="3817820803587012641">"Adresse anzeigen"</string>
+ <string name="map_custom" msgid="6184363799976265281">"<xliff:g id="CUSTOM">%s</xliff:g>-Adresse anzeigen"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Über AIM chatten"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Über Windows Live chatten"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Über Yahoo! chatten"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Über Skype chatten"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Über QQ chatten"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Über Google Talk chatten"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Über ICQ chatten"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Über Jabber chatten"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"Löschen"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Namensfelder maximieren oder minimieren"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Alle Kontakte"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Markiert"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personalisieren"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontakt"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Alle weiteren Kontakte"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Alle Kontakte"</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_warn_remove_ungrouped" msgid="8872290721676651414">"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="savingDisplayGroups" msgid="2133152192716475939">"Anzeigeoptionen werden gespeichert..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Fertig"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Abbrechen"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Von SIM-Karte importieren"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Import von <xliff:g id="FILENAME">%s</xliff:g> abbrechen?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Export von <xliff:g id="FILENAME">%s</xliff:g> abbrechen?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard-Import/-Export nicht abgebrochen"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Unbekannter Fehler"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" konnte nicht geöffnet werden: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Exportprogramm konnte nicht gestartet werden: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Es ist kein exportierbarer Kontakt vorhanden."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Beim Export ist ein Fehler aufgetreten: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Erforderlicher Dateiname ist zu lang (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"E/A-Fehler"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Nicht genügend Speicherplatz. Die Datei ist möglicherweise zu groß."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Die vCard konnte aus einem unerwarteten Grund nicht geparst werden."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Das Format wird nicht unterstützt."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Abrufen der Metadaten aus angegebenen vCards nicht möglich"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Eine oder mehrere Dateien können nicht importiert werden (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Export von <xliff:g id="FILENAME">%s</xliff:g> abgeschlossen"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Export von <xliff:g id="FILENAME">%s</xliff:g> abgebrochen"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Kontaktdaten werden exportiert."</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Datenbankinformationen konnten nicht abgerufen werden."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Es sind keine exportierbaren Kontakte vorhanden. Falls sich Kontakte auf Ihrem Telefon befinden, ist das Exportieren der Kontakte möglicherweise durch den Datenanbieter gesperrt."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Das Programm zum Erstellen der vCard wurde nicht richtig gestartet."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Export nicht möglich"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Die Kontaktdaten wurden nicht exportiert.\nGrund: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> wird importiert"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Lesen der vCard-Daten nicht möglich"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Lesen von vCard-Daten abgebrochen"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Import der vCard <xliff:g id="FILENAME">%s</xliff:g> abgeschlossen"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Import von <xliff:g id="FILENAME">%s</xliff:g> abgebrochen"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> wird demnächst importiert."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Die Datei wird in Kürze importiert."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Die vCard-Importanfrage wurde abgelehnt. Bitte versuchen Sie es später erneut."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> wird demnächst exportiert."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Die vCard-Exportanfrage wurde abgelehnt. Bitte versuchen Sie es später erneut."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"Kontakt"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Caching der vCard(s) in lokalen temporären Speicher wird durchgeführt. Der eigentliche Import beginnt gleich."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Importieren der vCard nicht möglich"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontakt erhalten per NCF"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Kontakte exportieren?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Caching läuft..."</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g> wird importiert: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Einstellungen"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Sichtbare Kontakte teilen"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Import/Export von Kontakten"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Kontakte importieren"</string>
+ <string name="share_error" msgid="948429331673358107">"Dieser Kontakt kann nicht geteilt werden."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Suche"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kontakte zur Ansicht"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kontakte zur Ansicht"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriten"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Keine Kontakte"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"\"Häufig kontaktiert\" löschen"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM-Karte auswählen"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importieren/Exportieren"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blockierte Nummern"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"über <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> über <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Suche zurücksetzen"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 15fa54f..e973aa8 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Ορισμός ως προεπιλογή"</string>
<string name="clear_default" msgid="7193185801596678067">"Εκκαθάριση προεπιλεγμένων"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Το κείμενο αντιγράφηκε"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Να απορριφθούν οι αλλαγές που πραγματοποιήσατε και να τερματιστεί η επεξεργασία;"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Να απορριφθούν οι αλλαγές;"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Απόρριψη"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Συνέχεια επεξεργασίας"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Ακύρωση"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Αναζήτηση επαφών"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Κατάργηση επαφών"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Σχετικά με"</string>
<string name="send_message" msgid="8938418965550543196">"Αποστολή μηνύματος"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Δημιουργία προσωπικού αντιγράφου..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Χθες"</string>
<string name="tomorrow" msgid="6241969467795308581">"Αύριο"</string>
<string name="today" msgid="8041090779381781781">"Σήμερα"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Σήμερα στις <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Μηνύματα"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Οργανώστε τη λίστα σας"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Απαλλαγείτε από τις διπλότυπες εγγραφές & ομαδοποιήστε επαφές ανά ετικέτα"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Το κείμενο αντιγράφηκε"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Αντιγραφή στο πρόχειρο"</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="8563753966926932052">"Κλήση"</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="5745314124619636674">"Κλήση φαξ"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Αποστολή μηνύματος κειμένου"</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="3888842199855843152">"Αποστολή μηνύματος κειμένου σε φαξ"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Διαγραφή ατόμων με συχνή επικοινωνία;"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Διαγρ. ατόμων με συχνή επικοινωνία…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Διαθέσιμος"</string>
+ <string name="status_away" msgid="1838861100379804730">"Απουσιάζω"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Απασχολημένος"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Επαφές"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Άλλο"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Κατάλογος"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Όλες οι επαφές"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Αναζήτηση…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Βρέθηκαν περισσότερα από <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Δεν υπάρχουν επαφές"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">Βρέθηκαν <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="one">Βρέθηκε 1</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Γρήγορη επαφή για <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Χωρίς όνομα)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Επαφές που έχετε συχνή επικοινωνία"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Προβολή επαφής"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Όλες οι επαφές με αριθμούς τηλεφώνου"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Προβολή ενημερώσεων"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Όνομα"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Ψευδώνυμο"</string>
+ <string name="full_name" msgid="6602579550613988977">"Όνομα"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Όνομα σε φωνητική γραφή"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Φωνητική γραφή ονόματος πατρός"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Τηλέφωνο"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Διεύθυνση ηλεκτρονικού ταχυδρομείου"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Διεύθυνση"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Ανταλ.άμεσων μην.(IM)"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Οργανισμός"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Σχέση"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Μήνυμα κειμένου"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Διεύθυνση"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Εταιρεία"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Τίτλος"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Σημειώσεις"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Ιστότοπος"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"Μήνυμα ηλεκτρονικού ταχυδρομείου"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου προς <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Διεύθυνση ηλεκτρονικού ταχυδρομείου"</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="map_home" msgid="1243547733423343982">"Προβολή διεύθυνσης οικίας"</string>
+ <string name="map_work" msgid="1360474076921878088">"Προβολή διεύθυνσης εργασίας"</string>
+ <string name="map_other" msgid="3817820803587012641">"Προβολή διεύθυνσης"</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="description_minus_button" msgid="6908099247930477551">"διαγραφή"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Ανάπτυξη ή σύμπτυξη πεδίων ονομάτων"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Όλες οι επαφές"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Με αστέρι"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Προσαρμογή"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Επαφή"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Όλες οι άλλες επαφές"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Όλες οι επαφές"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Η κατάργηση της ομάδας \"<xliff:g id="GROUP">%s</xliff:g>\" από τον συγχρονισμό θα καταργήσει επίσης και τις επαφές χωρίς ομαδοποίηση από τον συγχρονισμό."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Αποθήκευση επιλογών προβολής…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Τέλος"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Ακύρωση"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Εισαγωγή από κάρτα SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Να ακυρωθεί η εισαγωγή του αρχείου <xliff:g id="FILENAME">%s</xliff:g>;"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Να ακυρωθεί η εξαγωγή του αρχείου <xliff:g id="FILENAME">%s</xliff:g>;"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Αδ.ακύρ.εισαγ./εξαγ.vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Άγνωστο σφάλμα."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Δεν ήταν δυνατό το άνοιγμα του αρχείου \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Δεν ήταν δυνατή η έναρξη του εξαγωγέα: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Δεν υπάρχει επαφή με δυνατότητα εξαγωγής."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Προέκυψε κάποιο σφάλμα κατά την εξαγωγή: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Το απαιτούμενο όνομα αρχείου είναι πάρα πολύ μεγάλο (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Σφάλμα I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Δεν υπάρχει αρκετή μνήμη. Το αρχείο ενδέχεται να είναι πάρα πολύ μεγάλο."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Δεν ήταν δυνατή η ανάλυση της κάρτας vCard λόγω μη αναμενόμενης αιτίας."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Η μορφή δεν υποστηρίζεται."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Δεν ήταν δυνατή η συλλογή πληροφοριών μεταδεδομένων των καρτών vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Δεν ήταν δυνατή η εισαγωγή ενός ή περισσότερων αρχείων (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Η εξαγωγή του αρχείου <xliff:g id="FILENAME">%s</xliff:g> ολοκληρώθηκε."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Η εξαγωγή του αρχείου <xliff:g id="FILENAME">%s</xliff:g> ακυρώθηκε."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Εξαγωγή δεδομένων επαφών"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Δεν ήταν δυνατή η λήψη πληροφοριών βάσης δεδομένων."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Δεν υπάρχουν επαφές προς εξαγωγή. Αν υπάρχουν επαφές στο τηλέφωνό σας, ορισμένοι πάροχοι δεδομένων ενδέχεται να μην επιτρέπουν την εξαγωγή των επαφών από το τηλέφωνο."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Η έναρξη της vCard δεν ήταν σωστή."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Αδυναμία εξαγωγής"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Δεν έγινε εξαγωγή των δεδομένων επαφής.\nΑιτία: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Εισαγωγή <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Αδύν. ανάγν. δεδομ. vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Ακύρωση ανάγνωσης δεδομένων vCard"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Η εισαγωγή vCard ολοκληρώθηκε <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Η εισαγωγή του αρχείου <xliff:g id="FILENAME">%s</xliff:g> ακυρώθηκε"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Η <xliff:g id="FILENAME">%s</xliff:g> θα εισαχθεί σύντομα."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Η εισαγωγή του αρχείου θα γίνει σύντομα."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Το αίτημα εισαγωγής vCard απορρίφθηκε. Δοκιμάστε ξανά αργότερα."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Η <xliff:g id="FILENAME">%s</xliff:g> θα εξαχθεί σύντομα."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Το αίτημα εξαγωγής vCard απορρίφθηκε. Δοκιμάστε ξανά αργότερα."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"επαφή"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Αλλαγή vCard σε τοπικό χώρο προσωρινής αποθήκευσης. Η εισαγωγή θα ξεκινήσει σύντομα."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Δεν ήταν δυνατή η εισαγωγή κάρτας vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Λήψ.επ.μέσω ΕΚΠ"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Εξαγωγή επαφών;"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Προσωρινή αποθήκευση"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Εισαγωγή <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Ρυθμίσεις"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Κοινή χρήση ορατών επαφών"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Εισαγωγή/Εξαγωγή επαφών"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Εισαγωγή επαφών"</string>
+ <string name="share_error" msgid="948429331673358107">"Δεν είναι δυνατή η κοινή χρήση αυτής της επαφής."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Αναζήτηση"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Επαφές για εμφάνιση"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Επαφές για προβολή"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Αγαπ."</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Δεν υπάρχουν επαφές."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Διαγραφή ατόμ. με συχνή επικ."</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Επιλογή κάρτας SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Εισαγωγή/Εξαγωγή"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Αποκλεισμένοι αριθμοί"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"μέσω <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> μέσω <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Διαγραφή αναζητήσεων"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 72374d5..bbb74ef 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Set default"</string>
<string name="clear_default" msgid="7193185801596678067">"Clear default"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Text copied"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Discard your changes and quit editing?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Discard changes?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Discard"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Keep editing"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Cancel"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Search contacts"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Remove contacts"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"About"</string>
<string name="send_message" msgid="8938418965550543196">"Send message"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Creating a personal copy…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Yesterday"</string>
<string name="tomorrow" msgid="6241969467795308581">"Tomorrow"</string>
<string name="today" msgid="8041090779381781781">"Today"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Today at <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Messages"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organise your list"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Clean up duplicates & group contacts by label"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Text copied"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copy to clipboard"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Call <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Call home"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Call mobile"</string>
+ <string name="call_work" msgid="5328785911463744028">"Call work"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Call work fax"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Call home fax"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Call pager"</string>
+ <string name="call_other" msgid="8563753966926932052">"Call"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Call callback"</string>
+ <string name="call_car" msgid="3280537320306436445">"Call car"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Call company main"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Call ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Call main"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Call fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Call radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Call telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Call TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Call work mobile"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Call work pager"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Call <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Call MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Text <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Text home"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Text mobile"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Text work"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Text work fax"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Text home fax"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Text pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"Text"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Text callback"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Text car"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Text company main"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Text ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Text main"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Text fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Text radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Text telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Text TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Text work mobile"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Text work pager"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Text <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Text MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Clear frequently contacted?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Clearing frequently contacted…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Available"</string>
+ <string name="status_away" msgid="1838861100379804730">"Away"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Busy"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contacts"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Other"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Directory"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"All contacts"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Searching…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"More than <xliff:g id="COUNT">%d</xliff:g> found."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"No contacts"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> found</item>
+ <item quantity="one">1 found</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Quick contact for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(No name)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Frequently contacted"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"View contact"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"All contacts with phone numbers"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"View updates"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Name"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Nickname"</string>
+ <string name="full_name" msgid="6602579550613988977">"Name"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Name prefix"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Middle name"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Name suffix"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Phonetic name"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Phonetic middle name"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Phone"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Email"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Address"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relationship"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Text message"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Address"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Company"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Title"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notes"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Email home"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Email mobile"</string>
+ <string name="email_work" msgid="2807430017302722689">"Email work"</string>
+ <string name="email_other" msgid="3454004077967657109">"Email"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Email <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Email"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Street"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO box"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Neighbourhood"</string>
+ <string name="postal_city" msgid="6597491300084895548">"City"</string>
+ <string name="postal_region" msgid="6045263193478437672">"County"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postcode"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Country"</string>
+ <string name="map_home" msgid="1243547733423343982">"View home address"</string>
+ <string name="map_work" msgid="1360474076921878088">"View work address"</string>
+ <string name="map_other" msgid="3817820803587012641">"View address"</string>
+ <string name="map_custom" msgid="6184363799976265281">"View <xliff:g id="CUSTOM">%s</xliff:g> address"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chat using AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chat using Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chat using Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chat using Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chat using QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chat using Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chat using ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chat using Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"delete"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Expand or collapse name fields"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"All contacts"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Starred"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Customise"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contact"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"All other contacts"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"All contacts"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Remove sync group"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Add sync group"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"More groups…"</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Removing \"<xliff:g id="GROUP">%s</xliff:g>\" from sync will also remove any ungrouped contacts from sync."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Saving display options…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Done"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Cancel"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Import from SIM card"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Cancel import of <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Cancel export of <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Couldn\'t cancel vCard import/export"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Unknown error."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Couldn\'t open \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Couldn\'t start the exporter: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"There is no exportable contact."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"An error occurred during export: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Required filename is too long (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O error"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Not enough memory. The file may be too large."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Couldn\'t parse vCard for an unexpected reason."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"The format isn\'t supported."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Couldn\'t collect meta information of given vCard file(s)."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"One or more files couldn\'t be imported (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Finished exporting <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exporting <xliff:g id="FILENAME">%s</xliff:g> cancelled."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exporting contact data"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Couldn\'t get database information."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"There are no exportable contacts. If you do have contacts on your phone, some data providers may not allow the contacts to be exported from the phone."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"The vCard composer didn\'t start properly."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Couldn\'t export"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"The contact data wasn\'t exported.\nReason: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importing <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Couldn\'t read vCard data"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Reading vCard data cancelled"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Finished importing vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importing <xliff:g id="FILENAME">%s</xliff:g> cancelled"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> will be imported shortly."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"The file will be imported shortly."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard import request was rejected. Try again later."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> will be exported shortly."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard export request was rejected. Try again later."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contact"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Caching vCard(s) to local temporary storage. The actual import will start soon."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Couldn\'t import vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contact received over NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Export contacts?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Caching"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importing <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Settings"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Share visible contacts"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Import/export contacts"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Import contacts"</string>
+ <string name="share_error" msgid="948429331673358107">"This contact cannot be shared."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Search"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contacts to display"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contacts to display"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favourites"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"No contacts."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Clear frequents"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Select SIM card"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Import/export"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blocked numbers"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Clear search"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 72374d5..bbb74ef 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Set default"</string>
<string name="clear_default" msgid="7193185801596678067">"Clear default"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Text copied"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Discard your changes and quit editing?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Discard changes?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Discard"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Keep editing"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Cancel"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Search contacts"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Remove contacts"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"About"</string>
<string name="send_message" msgid="8938418965550543196">"Send message"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Creating a personal copy…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Yesterday"</string>
<string name="tomorrow" msgid="6241969467795308581">"Tomorrow"</string>
<string name="today" msgid="8041090779381781781">"Today"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Today at <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Messages"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organise your list"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Clean up duplicates & group contacts by label"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Text copied"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copy to clipboard"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Call <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Call home"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Call mobile"</string>
+ <string name="call_work" msgid="5328785911463744028">"Call work"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Call work fax"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Call home fax"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Call pager"</string>
+ <string name="call_other" msgid="8563753966926932052">"Call"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Call callback"</string>
+ <string name="call_car" msgid="3280537320306436445">"Call car"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Call company main"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Call ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Call main"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Call fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Call radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Call telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Call TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Call work mobile"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Call work pager"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Call <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Call MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Text <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Text home"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Text mobile"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Text work"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Text work fax"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Text home fax"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Text pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"Text"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Text callback"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Text car"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Text company main"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Text ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Text main"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Text fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Text radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Text telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Text TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Text work mobile"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Text work pager"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Text <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Text MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Clear frequently contacted?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Clearing frequently contacted…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Available"</string>
+ <string name="status_away" msgid="1838861100379804730">"Away"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Busy"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contacts"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Other"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Directory"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"All contacts"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Searching…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"More than <xliff:g id="COUNT">%d</xliff:g> found."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"No contacts"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> found</item>
+ <item quantity="one">1 found</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Quick contact for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(No name)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Frequently contacted"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"View contact"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"All contacts with phone numbers"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"View updates"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Name"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Nickname"</string>
+ <string name="full_name" msgid="6602579550613988977">"Name"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Name prefix"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Middle name"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Name suffix"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Phonetic name"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Phonetic middle name"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Phone"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Email"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Address"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relationship"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Text message"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Address"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Company"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Title"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notes"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Email home"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Email mobile"</string>
+ <string name="email_work" msgid="2807430017302722689">"Email work"</string>
+ <string name="email_other" msgid="3454004077967657109">"Email"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Email <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Email"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Street"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO box"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Neighbourhood"</string>
+ <string name="postal_city" msgid="6597491300084895548">"City"</string>
+ <string name="postal_region" msgid="6045263193478437672">"County"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postcode"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Country"</string>
+ <string name="map_home" msgid="1243547733423343982">"View home address"</string>
+ <string name="map_work" msgid="1360474076921878088">"View work address"</string>
+ <string name="map_other" msgid="3817820803587012641">"View address"</string>
+ <string name="map_custom" msgid="6184363799976265281">"View <xliff:g id="CUSTOM">%s</xliff:g> address"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chat using AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chat using Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chat using Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chat using Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chat using QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chat using Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chat using ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chat using Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"delete"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Expand or collapse name fields"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"All contacts"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Starred"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Customise"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contact"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"All other contacts"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"All contacts"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Remove sync group"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Add sync group"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"More groups…"</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Removing \"<xliff:g id="GROUP">%s</xliff:g>\" from sync will also remove any ungrouped contacts from sync."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Saving display options…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Done"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Cancel"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Import from SIM card"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Cancel import of <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Cancel export of <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Couldn\'t cancel vCard import/export"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Unknown error."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Couldn\'t open \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Couldn\'t start the exporter: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"There is no exportable contact."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"An error occurred during export: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Required filename is too long (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O error"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Not enough memory. The file may be too large."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Couldn\'t parse vCard for an unexpected reason."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"The format isn\'t supported."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Couldn\'t collect meta information of given vCard file(s)."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"One or more files couldn\'t be imported (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Finished exporting <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exporting <xliff:g id="FILENAME">%s</xliff:g> cancelled."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exporting contact data"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Couldn\'t get database information."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"There are no exportable contacts. If you do have contacts on your phone, some data providers may not allow the contacts to be exported from the phone."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"The vCard composer didn\'t start properly."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Couldn\'t export"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"The contact data wasn\'t exported.\nReason: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importing <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Couldn\'t read vCard data"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Reading vCard data cancelled"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Finished importing vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importing <xliff:g id="FILENAME">%s</xliff:g> cancelled"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> will be imported shortly."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"The file will be imported shortly."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard import request was rejected. Try again later."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> will be exported shortly."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard export request was rejected. Try again later."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contact"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Caching vCard(s) to local temporary storage. The actual import will start soon."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Couldn\'t import vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contact received over NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Export contacts?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Caching"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importing <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Settings"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Share visible contacts"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Import/export contacts"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Import contacts"</string>
+ <string name="share_error" msgid="948429331673358107">"This contact cannot be shared."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Search"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contacts to display"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contacts to display"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favourites"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"No contacts."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Clear frequents"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Select SIM card"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Import/export"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blocked numbers"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Clear search"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 72374d5..bbb74ef 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Set default"</string>
<string name="clear_default" msgid="7193185801596678067">"Clear default"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Text copied"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Discard your changes and quit editing?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Discard changes?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Discard"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Keep editing"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Cancel"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Search contacts"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Remove contacts"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"About"</string>
<string name="send_message" msgid="8938418965550543196">"Send message"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Creating a personal copy…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Yesterday"</string>
<string name="tomorrow" msgid="6241969467795308581">"Tomorrow"</string>
<string name="today" msgid="8041090779381781781">"Today"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Today at <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Messages"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organise your list"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Clean up duplicates & group contacts by label"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Text copied"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copy to clipboard"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Call <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Call home"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Call mobile"</string>
+ <string name="call_work" msgid="5328785911463744028">"Call work"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Call work fax"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Call home fax"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Call pager"</string>
+ <string name="call_other" msgid="8563753966926932052">"Call"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Call callback"</string>
+ <string name="call_car" msgid="3280537320306436445">"Call car"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Call company main"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Call ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Call main"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Call fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Call radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Call telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Call TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Call work mobile"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Call work pager"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Call <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Call MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Text <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Text home"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Text mobile"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Text work"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Text work fax"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Text home fax"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Text pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"Text"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Text callback"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Text car"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Text company main"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Text ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Text main"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Text fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Text radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Text telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Text TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Text work mobile"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Text work pager"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Text <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Text MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Clear frequently contacted?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Clearing frequently contacted…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Available"</string>
+ <string name="status_away" msgid="1838861100379804730">"Away"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Busy"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contacts"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Other"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Directory"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"All contacts"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Searching…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"More than <xliff:g id="COUNT">%d</xliff:g> found."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"No contacts"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> found</item>
+ <item quantity="one">1 found</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Quick contact for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(No name)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Frequently contacted"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"View contact"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"All contacts with phone numbers"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"View updates"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Name"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Nickname"</string>
+ <string name="full_name" msgid="6602579550613988977">"Name"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Name prefix"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Middle name"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Name suffix"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Phonetic name"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Phonetic middle name"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Phone"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Email"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Address"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relationship"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Text message"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Address"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Company"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Title"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notes"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Email home"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Email mobile"</string>
+ <string name="email_work" msgid="2807430017302722689">"Email work"</string>
+ <string name="email_other" msgid="3454004077967657109">"Email"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Email <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Email"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Street"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO box"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Neighbourhood"</string>
+ <string name="postal_city" msgid="6597491300084895548">"City"</string>
+ <string name="postal_region" msgid="6045263193478437672">"County"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postcode"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Country"</string>
+ <string name="map_home" msgid="1243547733423343982">"View home address"</string>
+ <string name="map_work" msgid="1360474076921878088">"View work address"</string>
+ <string name="map_other" msgid="3817820803587012641">"View address"</string>
+ <string name="map_custom" msgid="6184363799976265281">"View <xliff:g id="CUSTOM">%s</xliff:g> address"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chat using AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chat using Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chat using Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chat using Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chat using QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chat using Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chat using ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chat using Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"delete"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Expand or collapse name fields"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"All contacts"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Starred"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Customise"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contact"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"All other contacts"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"All contacts"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Remove sync group"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Add sync group"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"More groups…"</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Removing \"<xliff:g id="GROUP">%s</xliff:g>\" from sync will also remove any ungrouped contacts from sync."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Saving display options…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Done"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Cancel"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Import from SIM card"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Cancel import of <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Cancel export of <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Couldn\'t cancel vCard import/export"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Unknown error."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Couldn\'t open \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Couldn\'t start the exporter: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"There is no exportable contact."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"An error occurred during export: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Required filename is too long (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O error"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Not enough memory. The file may be too large."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Couldn\'t parse vCard for an unexpected reason."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"The format isn\'t supported."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Couldn\'t collect meta information of given vCard file(s)."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"One or more files couldn\'t be imported (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Finished exporting <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exporting <xliff:g id="FILENAME">%s</xliff:g> cancelled."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exporting contact data"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Couldn\'t get database information."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"There are no exportable contacts. If you do have contacts on your phone, some data providers may not allow the contacts to be exported from the phone."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"The vCard composer didn\'t start properly."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Couldn\'t export"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"The contact data wasn\'t exported.\nReason: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importing <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Couldn\'t read vCard data"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Reading vCard data cancelled"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Finished importing vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importing <xliff:g id="FILENAME">%s</xliff:g> cancelled"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> will be imported shortly."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"The file will be imported shortly."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard import request was rejected. Try again later."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> will be exported shortly."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard export request was rejected. Try again later."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contact"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Caching vCard(s) to local temporary storage. The actual import will start soon."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Couldn\'t import vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contact received over NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Export contacts?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Caching"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importing <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Settings"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Share visible contacts"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Import/export contacts"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Import contacts"</string>
+ <string name="share_error" msgid="948429331673358107">"This contact cannot be shared."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Search"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contacts to display"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contacts to display"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favourites"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"No contacts."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Clear frequents"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Select SIM card"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Import/export"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blocked numbers"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Clear search"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 7805c5e..8b38e36 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Establecer como predeterminado"</string>
<string name="clear_default" msgid="7193185801596678067">"Eliminar predeterminado"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"¿Deseas descartar los cambios y salir del editor?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"¿Deseas descartar los cambios?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Descartar"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Seguir editando"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Cancelar"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Buscar contactos"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Quitar contactos"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Información"</string>
<string name="send_message" msgid="8938418965550543196">"Enviar mensaje"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Creando una copia personal..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Ayer"</string>
<string name="tomorrow" msgid="6241969467795308581">"Mañana"</string>
<string name="today" msgid="8041090779381781781">"Hoy"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Hoy a la hora <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mensajes"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organiza tu lista"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Borra los contactos duplicados y agrupa los contactos por etiqueta"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copiar en el portapapeles"</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 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="8563753966926932052">"Llamar"</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="5745314124619636674">"Llamar a 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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Enviar texto"</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="3888842199855843152">"Enviar 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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"¿Borrar los contactos frecuentes?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Borrando contactos frecuentes…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Disponible"</string>
+ <string name="status_away" msgid="1838861100379804730">"Ausente"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Ocupado"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contactos"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Otro"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Directorio"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Todos los contactos"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Buscando..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Se encontraron más de <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"No hay contactos"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">Se encontraron <xliff:g id="COUNT">%d</xliff:g>.</item>
+ <item quantity="one">Se encontró 1.</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Contacto rápido de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Sin nombre)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Contactado con frecuencia"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Ver contacto"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Todos los contactos con número de teléfono"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Ver actualizaciones"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nombre"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Apodo"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nombre"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Nombre fonético"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Segundo nombre fonético"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Teléfono"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Correo"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Dirección"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Mensajería instantánea"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organización"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relación"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Mensaje de texto"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Dirección"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Título"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notas"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Sitio web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Correo personal"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Correo celular"</string>
+ <string name="email_work" msgid="2807430017302722689">"Correo laboral"</string>
+ <string name="email_other" msgid="3454004077967657109">"Enviar correo"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Enviar correo a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Correo"</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="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="3817820803587012641">"Ver 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="description_minus_button" msgid="6908099247930477551">"Eliminar"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Expandir o contraer campos de nombre"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Todos los contactos"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Destacado"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personalizar"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contacto"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Todos los demás contactos"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Todos los contactos"</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_warn_remove_ungrouped" msgid="8872290721676651414">"La eliminación de \"<xliff:g id="GROUP">%s</xliff:g>\" de la sincronización también eliminará de la sincronización todos los contactos que no estén agrupados."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Guardando opciones de visualización..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Finalizar"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Cancelar"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importar de la tarjeta SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"¿Deseas cancelar la importación de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"¿Deseas cancelar la exportación de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"No se canceló la impor./expor. de vCard."</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Error desconocido"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"No se pudo abrir \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"No se pudo iniciar el exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"No hay contactos para exportar."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Se produjo un error durante la exportación: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"El nombre de archivo requerido es demasiado largo (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Error de E/S"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Memoria insuficiente (es probable que el archivo sea muy grande)."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"No se pudo analizar el archivo vCard debido a un error inesperado."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"El formato no es compatible."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"No se pudieron recopilar los metadatos de los archivos vCard proporcionados."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"No se pudieron importar uno o más archivos (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Finalizó la exportación de <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Se canceló la exportación de <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportando datos de contacto"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"No se pudo obtener la información de la base de datos."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"No hay contactos exportables. Si tienes contactos en el dispositivo, es posible que algunos proveedores de datos no permitan la exportación de contactos desde el dispositivo."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"El compositor de la vCard no se inició correctamente."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"No se pudo exportar"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"No se exportaron los datos del contacto.\nMotivo: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importando <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"No se pudieron leer los datos de vCard."</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Se canceló la lectura de datos de la vCard."</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Finalizó la importación de la vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Se canceló la importación de <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> se importará en breve."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"El archivo se importará en breve."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Se rechazó la solicitud de importación de la vCard. Vuelve a intentarlo más tarde."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> se exportará en breve."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Se rechazó la solicitud de exportación de la vCard. Vuelve a intentarlo más tarde."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contacto"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Almacenando vCard(s) en caché local temporal. La importación comenzará pronto."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"No se pudo importar archivo de vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contac recib NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"¿Exportar contactos?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Almacenando en caché"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importando <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Configuración"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Compartir contactos visibles"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Imp./exp. contactos"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importar contactos"</string>
+ <string name="share_error" msgid="948429331673358107">"No es posible compartir este contacto."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Buscar"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contactos para mostrar"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contactos para mostrar"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"No hay contactos."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Borrar contactos frecuentes"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Seleccionar tarjeta SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importar/Exportar"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Números bloqueados"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"a través de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> a través de <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Borrar la búsqueda"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 3461637..5326b0a 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Establecer como predeterminado"</string>
<string name="clear_default" msgid="7193185801596678067">"Borrar predeterminado"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"¿Descartar los cambios y dejar de editar?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"¿Descartar cambios?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Descartar"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Seguir editando"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Cancelar"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Buscar contactos"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Quitar contactos"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Información"</string>
<string name="send_message" msgid="8938418965550543196">"Enviar mensaje"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Creando una copia personal..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Ayer"</string>
<string name="tomorrow" msgid="6241969467795308581">"Mañana"</string>
<string name="today" msgid="8041090779381781781">"Hoy"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Hoy a las <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mensajes"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organiza tu lista"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Elimina los contactos que tengas repetidos y agrúpalos por etiqueta"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copiar en el portapapeles"</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 al busca"</string>
+ <string name="call_other" msgid="8563753966926932052">"Llamar"</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="5745314124619636674">"Llamar a 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 busca 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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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 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 SMS al fax del trabajo"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Enviar SMS al fax de casa"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Enviar SMS al busca"</string>
+ <string name="sms_other" msgid="806127844607642331">"Enviar SMS"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Enviar SMS a devolución de llamada"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Enviar SMS al coche"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Enviar SMS al teléfono principal de la empresa"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Enviar SMS a RDSI"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Enviar SMS al teléfono principal"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Enviar SMS a fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Enviar SMS a la radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Enviar SMS al télex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Enviar SMS a TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Enviar SMS al móvil del trabajo"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Enviar SMS al busca 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 SMS a MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"¿Borrar contactos frecuentes?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Borrando contactos frecuentes…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Disponible"</string>
+ <string name="status_away" msgid="1838861100379804730">"Ausente"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Ocupado"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contactos"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Otro"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Directorio"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Todos los contactos"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Buscando..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Se han encontrado más de <xliff:g id="COUNT">%d</xliff:g> contactos."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"No hay contactos"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> contactos encontrados</item>
+ <item quantity="one">1 contacto encontrado</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Contacto rápido de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Sin nombre)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Contactos frecuentes"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Ver contacto"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Todos los contactos con número"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Ver actualizaciones"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nombre"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Seudónimo"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nombre"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Nombre fonético"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Segundo nombre fonético"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Teléfono"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Correo"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Dirección"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Chat"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organización"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relación"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Mensaje de texto"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Dirección"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Cargo"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notas"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Sitio web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Enviar correo a casa"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Enviar correo al móvil"</string>
+ <string name="email_work" msgid="2807430017302722689">"Enviar correo al trabajo"</string>
+ <string name="email_other" msgid="3454004077967657109">"Enviar correo"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Enviar correo a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Correo"</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="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="3817820803587012641">"Ver dirección"</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="description_minus_button" msgid="6908099247930477551">"eliminar"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Ampliar o contraer campos de nombre"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Todos los contactos"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Destacados"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personalizar"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contacto"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Todos los demás contactos"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Todos los contactos"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Si eliminas \"<xliff:g id="GROUP">%s</xliff:g>\" de las sincronización, también se eliminarán todos los contactos no agrupados."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Guardando opciones de visualización…"</string>
+ <string name="menu_done" msgid="796017761764190697">"OK"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Cancelar"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importar contactos desde la tarjeta SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"¿Seguro que quieres cancelar la importación de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"¿Seguro que quieres cancelar la exportación de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Error al cancelar la importación/exportación de vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Error desconocido"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"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="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"No se ha podido iniciar la exportación: (\"<xliff:g id="EXACT_REASON">%s</xliff:g>\")."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"No hay contactos que exportar."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Se ha producido un error durante la exportación (\"<xliff:g id="EXACT_REASON">%s</xliff:g>\")."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"El nombre de archivo obligatorio es demasiado largo (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Error de E/S"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"No hay suficiente espacio de memoria (el archivo puede ser demasiado grande)."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"No se ha podido analizar el archivo vCard debido a un error inesperado."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"No se admite este formato."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"No se han podido recuperar los metadatos de los archivos vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"No se ha podido importar uno o más archivos (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Exportación de <xliff:g id="FILENAME">%s</xliff:g> finalizada"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Se ha cancelado la exportación de <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportando datos de contacto"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"No se ha podido obtener información de la base de datos."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"No hay contactos que exportar. Si ya tienes contactos en el teléfono, es posible que el proveedor de datos no permita que se exporten los contactos del teléfono."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"El redactor de vCard no se ha iniciado correctamente."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Error al exportar"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"No se han exportado los datos de contactos (\nmotivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\")."</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importando <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"No se han podido leer los datos de la vCard."</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Lectura de datos de vCard cancelada"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Importación de <xliff:g id="FILENAME">%s</xliff:g> de vCard finalizada"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Se ha cancelado la importación de <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> se importará en breve."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"El archivo se importará en breve."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Se ha rechazado la solicitud de importación de vCard. Inténtalo de nuevo más tarde."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> se exportará en breve."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Se ha rechazado la solicitud de exportación de vCard. Inténtalo de nuevo más tarde."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contacto"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Se están almacenando los archivos vCard en la caché. La importación empezará pronto."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Error al importar el archivo vCard"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contacto recibido por NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"¿Exportar contactos?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Almacenando en caché"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importando <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Ajustes"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Compartir contactos visibles"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importar/exportar contactos"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importar contactos"</string>
+ <string name="share_error" msgid="948429331673358107">"No se puede compartir este contacto."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Buscar"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contactos que mostrar"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contactos que mostrar"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"No hay contactos."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Borrar frecuentes"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Seleccionar tarjeta SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importar/exportar"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Números bloqueados"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"con <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> con <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Borrar la búsqueda"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
index 0799d56..9f7b78a 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et-rEE/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Määra vaikeseadeks"</string>
<string name="clear_default" msgid="7193185801596678067">"Kustuta vaikeseaded"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Tekst on kopeeritud"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Kas soovite muudatustest loobuda ja muutmise lõpetada?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Kas soovite muudatustest loobuda?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Loobu"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Jätka muutmist"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Tühista"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Otsige kontakte"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Kontaktide eemaldamine"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Teave"</string>
<string name="send_message" msgid="8938418965550543196">"Saada sõnum"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Isikliku koopia loomine ..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Eile"</string>
<string name="tomorrow" msgid="6241969467795308581">"Homme"</string>
<string name="today" msgid="8041090779381781781">"Täna"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Täna kell <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Sõnumid"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Korraldage oma loendit"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Eemaldab duplikaadid ja grupeerib kontaktid sildi alusel"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Tekst on kopeeritud"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopeeri lõikelauale"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Helista numbrile <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Helista kodu telefoninumbrile"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Helista mobiilinumbrile"</string>
+ <string name="call_work" msgid="5328785911463744028">"Helista töönumbrile"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Helista tööfaksinumbrile"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Helista kodu faksinumbrile"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Helista piiparinumbrile"</string>
+ <string name="call_other" msgid="8563753966926932052">"Helista"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Helista tagasihelistusnumbrile"</string>
+ <string name="call_car" msgid="3280537320306436445">"Helista autotelefoninumbrile"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Helista ettevõtte põhinumbrile"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Helista ISDN-telefoninumbrile"</string>
+ <string name="call_main" msgid="6082900571803441339">"Helista põhinumbrile"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Helista faksinumbrile"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Helista raadiotelefoninumbrile"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Helista teleksinumbrile"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Helista TTY-/TDD-numbrile"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Helista töömobiilinumbrile"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Helista tööpiiparinumbrile"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Helista numbrile <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Helista MMS-i numbrile"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Saada SMS numbrile <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Saada SMS kodu telefoninumbrile"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Saada SMS mobiilinumbrile"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Saada SMS töönumbrile"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Saada SMS tööfaksinumbrile"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Saada SMS kodusele faksinumbrile"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Saada SMS piiparinumbrile"</string>
+ <string name="sms_other" msgid="806127844607642331">"SMS"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Saada SMS tagasihelistusnumbrile"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Saada SMS autotelefoninumbrile"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Saada SMS ettevõtte peamisele telefoninumbrile"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Saada SMS ISDN-telefoninumbrile"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Saada SMS põhinumbrile"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Saada SMS faksinumbrile"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Saada SMS raadiotelefoninumbrile"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Saada SMS teleksinumbrile"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Saada SMS TTY-/TDD-numbrile"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Saada SMS töömobiilinumbrile"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Saada SMS tööpiiparinumbrile"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Saada SMS numbrile <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Saada MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Kas kustutada sagedased kontaktid?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Saged. kontaktide kustutamine ..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Saadaval"</string>
+ <string name="status_away" msgid="1838861100379804730">"Eemal"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Hõivatud"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontaktid"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Muu"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Kataloog"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Kõik kontaktid"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Otsimine ..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Leitud rohkem kui <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Kontakte pole"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">Leiti <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="one">Leiti 1</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Kiirkontakt: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Nimi puudub)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Sageli valitud kontaktid"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Vaadake kontakti"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Kõik telefoninumbritega kontaktid"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Kuva värskendused"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nimi"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Hüüdnimi"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nimi"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Nime eesliide"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Teine nimi"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Nime järelliide"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Foneetiline nimi"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Foneetiline keskmine nimi"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-post"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Aadress"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM (Kiirsuhtlus)"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisatsioon"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Suhe"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Tekstsõnum"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Aadress"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Ettevõte"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Pealkiri"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Märkused"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Veebisait"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Saada meilisõnum kodusele aadressile"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Saada meilisõnum mobiilile"</string>
+ <string name="email_work" msgid="2807430017302722689">"Saada meiliaadress tööaadressile"</string>
+ <string name="email_other" msgid="3454004077967657109">"E-post"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Saada meilisõnum aadressile <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-post"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Tänav"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Postkast"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Naabruskond"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Linn"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Riik"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Sihtnumber"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Riik"</string>
+ <string name="map_home" msgid="1243547733423343982">"Vaata kodu aadressi"</string>
+ <string name="map_work" msgid="1360474076921878088">"Vaata tööaadressi"</string>
+ <string name="map_other" msgid="3817820803587012641">"Vaata aadressi"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Vaata <xliff:g id="CUSTOM">%s</xliff:g> aadressi"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Vestle AIM-i kasutades"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Vestle Windows Live\'i abil"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Vestle Yahoo abil"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Vestle Skype\'i abil"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Vestle QQ abil"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Vestle Google Talki kasutades"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Vestle ICQ-d kasutades"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Vestle Jabberi abil"</string>
+ <string name="chat" msgid="9025361898797412245">"Vestlus"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"kustutamine"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Nimeväljade laiendamine või ahendamine"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Kõik kontaktid"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Tärniga tähistatud"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Kohanda"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontakt"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Kõik teised kontaktid"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Kõik kontaktid"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Eemalda sünkroonimisrühm"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Lisa sünkroonimisrühm"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Rohkem rühmi ..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Rühma „<xliff:g id="GROUP">%s</xliff:g>” eemaldamisel sünkroonimisest eemaldatakse sünkroonimisest ka kõik rühmitamata kontaktid."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Kuvavalikute salvestamine ..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Valmis"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Tühista"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Impordi SIM-kaardilt"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Kas tühistada faili <xliff:g id="FILENAME">%s</xliff:g> importimine?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Kas tühistada faili <xliff:g id="FILENAME">%s</xliff:g> eksportimine?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCardi impordi/ekspordi tühist. ebaõnn."</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Tundmatu viga."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Faili „<xliff:g id="FILE_NAME">%s</xliff:g>” ei saa avada: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Eksportijat ei saa lähtestada: „<xliff:g id="EXACT_REASON">%s</xliff:g>”."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Eksporditavad kontaktid puuduvad."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Viga eksportimisel: „<xliff:g id="EXACT_REASON">%s</xliff:g>”."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Kohustuslik failinimi on liiga pikk („<xliff:g id="FILENAME">%s</xliff:g>”)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O viga"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Pole piisavalt mälu. Fail võib olla liiga suur."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Ootamatul põhjusel vCardi sõelumine ebaõnnestus."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Vormingut ei toetata."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"vCardi faili(de) metaandmete kogumine ebaõnnestus."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Vähemalt ühe faili importimine ebaõnnestus (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Faili <xliff:g id="FILENAME">%s</xliff:g> eksportimine on lõpetatud."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Faili <xliff:g id="FILENAME">%s</xliff:g> eksportimine tühistati."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Kontaktandmete eksportimine"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Andmebaasiteabe hankimine ebaõnnestus."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Eksporditavaid kontakte pole. Kui teil siiski on telefonis kontakte, ei pruugi mõned andmesidepakkujad kontaktide eksportimist telefonist lubada."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCardi helilooja ei käivitunud korralikult."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Eksport ebaõnnestus"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Kontaktandmeid ei eksporditud.\nPõhjus: „<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importimine: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCardi andmete lugemine ebaõnnestus"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCardi andmete lugemine tühistati"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCardi faili <xliff:g id="FILENAME">%s</xliff:g> importimine on lõpetatud"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Faili <xliff:g id="FILENAME">%s</xliff:g> importimine tühistati"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Fail <xliff:g id="FILENAME">%s</xliff:g> imporditakse peagi."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Fail imporditakse peagi."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCardi importimistaotlus lükati tagasi. Proovige hiljem uuesti."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Fail <xliff:g id="FILENAME">%s</xliff:g> eksporditakse peagi."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCardi eksportimistaotlus lükati tagasi. Proovige hiljem uuesti."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontakt"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCardi(de) vahemälustamine kohalikku ajutisse mäluruumi. Tegelik importimine algab peagi."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCardi importimine ebaõnnestus."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontakt võeti vastu NFC kaudu"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Eksportida kontakt?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Vahemällu salvestamine"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importimine: <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Seaded"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Jaga nähtavaid kontakte"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Kontaktide import/eksport"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Kontaktide importimine"</string>
+ <string name="share_error" msgid="948429331673358107">"Seda kontakti ei saa jagada."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Otsing"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kuvatavad kontaktisikud"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kuvatavad kontaktid"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Lemmikud"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Kontaktid puuduvad."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Sagedaste kustutamine"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM-kaardi valimine"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Import/eksport"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blokeeritud numbrid"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"allika <xliff:g id="SOURCE">%1$s</xliff:g> kaudu"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> allika <xliff:g id="SOURCE">%2$s</xliff:g> kaudu"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Otsingu kustutamine"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index 0b9d40e..908fd30 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Ezarri lehenetsi gisa"</string>
<string name="clear_default" msgid="7193185801596678067">"Garbitu metodo lehenetsia"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Testua kopiatu da"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Aldaketak baztertu eta editatzeko modutik irten nahi duzu?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Aldaketak baztertu nahi dituzu?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Baztertu"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Jarraitu editatzen"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Utzi"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> (<xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>)"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Bilatu kontaktuetan"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Kendu kontaktuak"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Honi buruz"</string>
<string name="send_message" msgid="8938418965550543196">"Bidali mezua"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Kopia pertsonala sortzen…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Atzo"</string>
<string name="tomorrow" msgid="6241969467795308581">"Bihar"</string>
<string name="today" msgid="8041090779381781781">"Gaur"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Gaur (<xliff:g id="TIME_INTERVAL">%s</xliff:g>)"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mezuak"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Antolatu zerrenda"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Garbitu bikoiztuak eta taldekatu kontaktuak etiketen arabera"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Testua kopiatu da"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopiatu arbelean"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Deitu <xliff:g id="CUSTOM">%s</xliff:g> zenbakira"</string>
+ <string name="call_home" msgid="1990519474420545392">"Deitu etxera"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Deitu mugikorrera"</string>
+ <string name="call_work" msgid="5328785911463744028">"Deitu lanera"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Deitu laneko faxera"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Deitu etxeko faxera"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Deitu bilagailura"</string>
+ <string name="call_other" msgid="8563753966926932052">"Deitu"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Dei bidezko erantzuna"</string>
+ <string name="call_car" msgid="3280537320306436445">"Deitu autoko telefonora"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Deitu enpresaren zenbaki nagusira"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Deitu ISDN zenbakira"</string>
+ <string name="call_main" msgid="6082900571803441339">"Deitu zenbaki nagusira"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Deitu faxera"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Deitu irratira"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Deitu telexera"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Deitu TTY/TDD zenbakira"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Deitu laneko mugikorrera"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Deitu laneko bilagailura"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Deitu <xliff:g id="ASSISTANT">%s</xliff:g> zenbakira"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Deitu MMS zenbakira"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Bidali testu-mezua <xliff:g id="CUSTOM">%s</xliff:g> zenbakira"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Bidali testu-mezua etxera"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Bidali testu-mezua mugikorrera"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Bidali testu-mezua lanera"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Bidali testu-mezua laneko faxera"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Bidali testu-mezua etxeko faxera"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Bidali testu-mezua bilagailura"</string>
+ <string name="sms_other" msgid="806127844607642331">"Bidali testu-mezua"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Testu bidezko erantzuna"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Bidali testu-mezua autora"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Bidali testu-mezua enpresako zenbaki nagusira"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Bidali testu-mezua ISDN zenbakira"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Bidali testu-mezua zenbaki nagusira"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Bidali testu-mezua faxera"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Bidali testu-mezua irratira"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Bidali testu-mezua telexera"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Bidali testu-mezua TTY/TDD zenbakira"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Bidali testu-mezua laneko mugikorrera"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Bidali testu-mezua laneko bilagailura"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Bidali testu-mezua <xliff:g id="ASSISTANT">%s</xliff:g> zenbakira"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Bidali testu-mezua MMS zenbakira"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Sarri erabilitako kontaktuak garbitu?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Sarri erabilitako kontaktuak garbitzen…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Libre"</string>
+ <string name="status_away" msgid="1838861100379804730">"Kanpoan"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Okupatuta"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontaktuak"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Bestelakoak"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Direktorioa"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Kontaktu guztiak"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Bilatzen…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g> baino gehiago aurkitu dira."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Ez dago kontakturik"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> aurkitu dira</item>
+ <item quantity="one">Bat aurkitu da</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Honen kontaktu bizkorra: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Izenik ez)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Sarri kontaktatutakoak"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Ikusi kontaktua"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Telefono-zenbakiak dituzten kontaktu guztiak"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Ikusi berritasunak"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Izena"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Goitizena"</string>
+ <string name="full_name" msgid="6602579550613988977">"Izena"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Izenaren aurrizkia"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Bigarren izena"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Izenaren atzizkia"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Izen fonetikoa"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Bigarren izen fonetikoa"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefonoa"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Helbide elektronikoa"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Helbidea"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Erakundea"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Harremana"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Testu-mezua"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Helbidea"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Enpresa"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Lanpostua"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Oharrak"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Webgunea"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Bidali mezu elektronikoa etxera"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Bidali mezu elektronikoa mugikorrera"</string>
+ <string name="email_work" msgid="2807430017302722689">"Bidali mezu elektronikoa lanera"</string>
+ <string name="email_other" msgid="3454004077967657109">"Bidali mezu elektronikoa"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Bidali mezu elektronikoa <xliff:g id="CUSTOM">%s</xliff:g> helbidera"</string>
+ <string name="email" msgid="5668400997660065897">"Bidali mezu elektronikoa"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Kalea"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Posta-kutxa"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Auzoa"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Hiria"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Estatua"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Posta-kodea"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Herrialdea"</string>
+ <string name="map_home" msgid="1243547733423343982">"Ikusi etxeko helbidea"</string>
+ <string name="map_work" msgid="1360474076921878088">"Ikusi laneko helbidea"</string>
+ <string name="map_other" msgid="3817820803587012641">"Ikusi helbidea"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Ikusi <xliff:g id="CUSTOM">%s</xliff:g> helbidea"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Txateatu AIM bidez"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Txateatu Windows Live bidez"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Txateatu Yahoo bidez"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Txateatu Skype bidez"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Txateatu QQ bidez"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Txateatu Google Talk bidez"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Txateatu ICQ bidez"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Txateatu Jabber bidez"</string>
+ <string name="chat" msgid="9025361898797412245">"Txata"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"ezabatu"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Zabaldu edo tolestu izenen eremuak"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Kontaktu guztiak"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Izardunak"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Pertsonalizatua"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Hautatutako kontaktua"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Gainerako kontaktuak"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Kontaktu guztiak"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Kendu sinkronizazio-taldea"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Gehitu sinkronizazio-taldea"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Talde gehiago…"</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"\"<xliff:g id="GROUP">%s</xliff:g>\" sinkronizaziotik kentzen baduzu, talderik gabeko kontaktu guztiak ere ezabatuko dira."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Bistaratze-aukerak gordetzen…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Eginda"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Utzi"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Inportatu SIM txarteletik"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> fitxategiaren inportazioa bertan behera utzi nahi duzu?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> fitxategiaren esportazioa bertan behera utzi nahi duzu?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Ezin da vCard inportazioa edo esportazioa utzi"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Errore ezezaguna."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Ezin izan da \"<xliff:g id="FILE_NAME">%s</xliff:g>\" ireki. Arrazoia: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Ezin izan da esportatzailea hasi. Arrazoia: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Ez dago esporta daitekeen kontakturik."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Errore bat gertatu da esportatu bitartean. Arrazoia: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Beharrezko fitxategi-izena luzeegia da (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Sarrera- edo irteera-errorea"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Ez dago behar adina memoria. Baliteke fitxategia handiegia izatea."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Ezin izan da vCard txartela analizatu ustekabeko arrazoiren batengatik."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Formatua ez da bateragarria."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Ezin izan da emandako vCard txartelaren fitxategien meta-informazioa bildu."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Ezin izan da fitxategi bat edo gehiago inportatu (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Amaitu <xliff:g id="FILENAME">%s</xliff:g> esportatzen."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> fitxategia esportatzeari utzi zaio."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Kontaktuen datuak esportatzen"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Ezin izan da datu-baseko informazioa lortu."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Ez dago esporta daitekeen kontakturik. Telefonoan kontaktuak badituzu, baliteke datu-hornitzaileek kontaktuak telefonotik esportatzen ez uztea."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard txartelen idazlea ez da behar bezala hasi."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Ezin izan da esportatu"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Ez dira kontaktuaren datuak esportatu.\nArrazoia: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> inportatzen"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Ezin izan dira vCard datuak irakurri"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard datuen irakurketa utzi egin da"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"<xliff:g id="FILENAME">%s</xliff:g> vCard fitxategia inportatzen amaitu da"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> fitxategiaren inportazioa utzi egin da"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> fitxategia laster inportatuko da."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Fitxategia laster inportatuko da."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard fitxategia inportatzeko eskaera ukatu da. Saiatu geroago."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> fitxategia laster esportatuko da."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard fitxategia esportatzeko eskaera ukatu da. Saiatu berriro geroago."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontaktua"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard-ak aldi baterako biltegi lokalaren cachean gordetzen ari dira. Inportazioa bera laster hasiko da."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Ezin izan da vCard fitxategia inportatu."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontaktua NFC bidez jaso da"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Kontaktuak esportatu nahi dituzu?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Cachean gordetzen"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g> inportatzen: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Ezarpenak"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Partekatu ikusgai dauden kontaktuak"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Inportatu edo esportatu kontaktuak"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Inportatu kontaktuak"</string>
+ <string name="share_error" msgid="948429331673358107">"Ezin da kontaktua partekatu."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Bilatu"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Bistaratzeko kontaktuak"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Bistaratzeko kontaktuak"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Gogokoak"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Ez dago kontakturik."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Garbitu sarri erabilitakoak"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Hautatu SIM txartela"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Inportatu/Esportatu"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blokeatutako zenbakiak"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g> bidez"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="SOURCE">%2$s</xliff:g> bidez"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Garbitu bilaketa"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index cf23fc4..9fb08d1 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"تنظیم پیشفرض"</string>
<string name="clear_default" msgid="7193185801596678067">"پاک کردن پیش فرضها"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"متن کپی شده"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"از تغییراتتان صرفنظر میکنید و از ویرایش خارج میشوید؟"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"از تغییرات صرفنظر شود؟"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"صرفنظر کردن"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"حفظ ویرایش"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"لغو"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"جستجوی مخاطبین"</string>
<string name="title_edit_group" msgid="8602752287270586734">"حذف مخاطبین"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"درباره"</string>
<string name="send_message" msgid="8938418965550543196">"ارسال پیام"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"ایجاد یک کپی شخصی..."</string>
- <string name="yesterday" msgid="6840858548955018569">"دیروز"</string>
<string name="tomorrow" msgid="6241969467795308581">"فردا"</string>
<string name="today" msgid="8041090779381781781">"امروز"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"امروز در <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"پیامها"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"سازماندهی فهرست"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"پاک کردن موارد تکراری و مخاطبین گروه بر اساس برچسب"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"متن کپی شده"</string>
+ <string name="copy_text" msgid="3257145021583508761">"کپی در بریدهدان"</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="8563753966926932052">"تماس"</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="5745314124619636674">"تماس با نمابر"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"ارسال متن"</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="3888842199855843152">"ارسال متن به نمابر"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"فهرست تماس مکرر با مخاطب پاک شود؟"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"در حال پاک کردن فهرست تماس مکرر..."</string>
+ <string name="status_available" msgid="5586870015822828392">"در دسترس"</string>
+ <string name="status_away" msgid="1838861100379804730">"غایب"</string>
+ <string name="status_busy" msgid="9147992455450257136">"مشغول"</string>
+ <string name="contactsList" msgid="8661624236494819731">"مخاطبین"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"سایر موارد"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"دایرکتوری"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"همه مخاطبین"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"در حال جستجو..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"بیش از <xliff:g id="COUNT">%d</xliff:g> مورد پیدا شد."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"مخاطبی موجود نیست"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> مورد پیدا شد</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> مورد پیدا شد</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"تماس سریع برای <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(بدون نام)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"اغلب تماس گرفته شده"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"مشاهده مخاطب"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"همه مخاطبین دارای شماره تلفن"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"مشاهده بهروزرسانیها"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"نام"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"نام مستعار"</string>
+ <string name="full_name" msgid="6602579550613988977">"نام"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"تلفظ نام"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"تلفظ نام میانی"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"تلفن"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"رایانامه"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"آدرس"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"سازمان"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"رابطه"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"پیام نوشتاری"</string>
+ <string name="postal_address" msgid="8765560217149624536">"آدرس"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"شرکت"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"عنوان"</string>
+ <string name="label_notes" msgid="8337354953278341042">"یادداشتها"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"وب سایت"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"رایانامه"</string>
+ <string name="email_custom" msgid="7548003991586214105">"رایانامه <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"رایانامه"</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="map_home" msgid="1243547733423343982">"مشاهده آدرس منزل"</string>
+ <string name="map_work" msgid="1360474076921878088">"مشاهده آدرس محل کار"</string>
+ <string name="map_other" msgid="3817820803587012641">"مشاهده آدرس"</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="description_minus_button" msgid="6908099247930477551">"حذف"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"بزرگ یا کوچک کردن قسمتهای نام"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"همه مخاطبین"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"ستارهدار"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"سفارشی کردن"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"مخاطب"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"همهٔ مخاطبین دیگر"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"همه مخاطبین"</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_warn_remove_ungrouped" msgid="8872290721676651414">"حذف \"<xliff:g id="GROUP">%s</xliff:g>\" از همگامسازی نیز هر گونه مخاطب گروهبندی نشدهای را از همگامسازی حذف میکند."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"در حال ذخیره گزینههای نمایش..."</string>
+ <string name="menu_done" msgid="796017761764190697">"تمام"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"لغو"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"وارد کردن از سیم کارت"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"وارد کردن <xliff:g id="FILENAME">%s</xliff:g> لغو شود؟"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"صادر کردن <xliff:g id="FILENAME">%s</xliff:g> لغو شود؟"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"نمیتوان وارد کردن/ صادر کردن کارت ویزیت را لغو کرد"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"خطای ناشناس."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" باز نشد: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"صادر کننده راهاندازی نشد: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"هیچ مخاطب قابل صدوری موجود نیست."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"خطایی در هنگام صادر کردن روی داد: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"نام فایل خیلی طولانی است (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"خطای ورودی/خروجی"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"حافظه کافی نیست. ممکن است فایل بسیار بزرگ باشد."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"تفسیر کارت ویزیت به دلیل پیشبینی نشدهای ممکن نیست."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"قالب پشتیبانی نمیشود."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"نمیتوان اطلاعات متای فایل کارت ویزیت داده شده را جمعآوری کرد."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"نمیتوان یک یا چند فایل را وارد کرد (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"صادر کردن <xliff:g id="FILENAME">%s</xliff:g> پایان یافت."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"صادر کردن <xliff:g id="FILENAME">%s</xliff:g> لغو شد."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"صدور اطلاعات مخاطب"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"نمیتوان اطلاعات پایگاه داده را دریافت کرد."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"هیچ مخاطب قابل صدوری وجود ندارد. اگر در گوشی خود مخاطبینی دارید، بعضی از ارائهدهندگان داده ممکن است اجازه ندهند تا مخاطبین از گوشی صادر شوند."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"سازنده فایل کارت ویزیت به درستی اجرا نشد."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"صادر نمیشود"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"دادههای مخاطب صادر نشد.\nعلت: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"وارد کردن <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"خواندن دادههای کارت ویزیت ممکن نیست"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"خواندن داده کارت ویزیت لغو شد"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"وارد کردن کارت ویزیت <xliff:g id="FILENAME">%s</xliff:g> پایان یافت"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"واردکردن <xliff:g id="FILENAME">%s</xliff:g> لغو شد"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> به زودی وارد میشود."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"فایل پس از مدت کوتاهی وارد میشود."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"درخواست وارد کردن کارت ویزیت رد شد. لطفاً بعداً امتحان کنید."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> به زودی صادر میشود."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"درخواست صدور کارت ویزیت رد شد. لطفاً بعداً امتحان کنید."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"مخاطب"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"در حال ذخیره کارتهای ویزیت در حافظه موقت محلی است. وارد کردن واقعی به زودی آغاز خواهد شد."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"وارد کردن کارت ویزیت انجام نشد."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"مخاطب از طریق NFC رسید"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"مخاطبین صادر شوند؟"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"در حال ذخیره در حافظهٔ پنهان"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"وارد کردن <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"تنظیمات"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"اشتراکگذاری مخاطبین قابل مشاهده"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"وارد کردن/صادر کردن مخاطبین"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"وارد کردن مخاطبین"</string>
+ <string name="share_error" msgid="948429331673358107">"این مخاطب قابل اشتراکگذاری نیست."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"جستجو"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"مخاطبین جهت نمایش"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"مخاطبین جهت نمایش"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"موارد دلخواه"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"مخاطبی موجود نیست."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"پاک کردن تماسهای مکرر"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"انتخاب سیمکارت"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"وارد کردن/صادر کردن"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"شمارههای مسدودشده"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"از طریق <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> از طریق <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"پاک کردن جستجو"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 48ae68c..9acec85 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Aseta oletukseksi"</string>
<string name="clear_default" msgid="7193185801596678067">"Poista oletus"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Teksti kopioitu"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Hylätäänkö muutokset ja lopetetaan muokkaaminen?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Hylätäänkö muutokset?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Hylkää"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Jatka muokkausta"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Peruuta"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Hae yhteystiedoista"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Poista yhteystiedot"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Tietoja"</string>
<string name="send_message" msgid="8938418965550543196">"Lähetä viesti"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Luodaan kopio..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Eilen"</string>
<string name="tomorrow" msgid="6241969467795308581">"Huomenna"</string>
<string name="today" msgid="8041090779381781781">"Tänään"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Tänään klo <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Viestit"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Järjestä luettelosi"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Poista kopiot ja ryhmittele yhteystiedot tunnisteen mukaan."</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Teksti kopioitu"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopioi leikepöydälle"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Soita: <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Soita kotinumeroon"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Soita matkapuhelimeen"</string>
+ <string name="call_work" msgid="5328785911463744028">"Soita työnumeroon"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Soita faksinumeroon (työ)"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Soita faksinumeroon (koti)"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Soita hakulaitteeseen"</string>
+ <string name="call_other" msgid="8563753966926932052">"Soita"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Soita takaisinsoittonumeroon"</string>
+ <string name="call_car" msgid="3280537320306436445">"Soita autopuhelimeen"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Soita yrityksen ensisijaiseen numeroon"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Soita ISDN-numeroon"</string>
+ <string name="call_main" msgid="6082900571803441339">"Soita ensisijaiseen numeroon"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Soita faksinumeroon"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Soita radiopuhelimeen"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Soita teleksinumeroon"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Soita tekstipuhelimeen"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Soita matkapuhelimeen (työ)"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Soita hakulaitteeseen (työ)"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Soita: <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Soita MMS-numeroon"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Lähetä tekstiviesti: <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Lähetä tekstiviesti kotinumeroon"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Lähetä tekstiviesti matkapuhelimeen"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Lähetä tekstiviesti työnumeroon"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Lähetä tekstiviesti faksinumeroon (työ)"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Lähetä tekstiviesti faksinumeroon (koti)"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Lähetä tekstiviesti hakulaitteeseen"</string>
+ <string name="sms_other" msgid="806127844607642331">"Tekstiviesti"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Lähetä tekstiviesti takaisinsoittonumeroon"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Lähetä tekstiviesti autopuhelimeen"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Lähetä tekstiviesti yrityksen ensisijaiseen numeroon"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Lähetä tekstiviesti ISDN-numeroon"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Lähetä tekstiviesti ensisijaiseen numeroon"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Lähetä tekstiviesti faksinumeroon"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Lähetä tekstiviesti radiopuhelimeen"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Lähetä tekstiviesti teleksinumeroon"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Lähetä tekstiviesti tekstipuhelimeen"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Lähetä tekstiviesti matkapuhelimeen (työ)"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Lähetä tekstiviesti hakulaitteeseen (työ)"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Lähetä tekstiviesti: <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Lähetä tekstiviesti MMS-numeroon"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Tyhjennetäänkö usein käytetyt?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Tyhjennetään usein käytetyt..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Tavoitettavissa"</string>
+ <string name="status_away" msgid="1838861100379804730">"Poissa"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Varattu"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Yhteystiedot"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Muu"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Hakemisto"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Kaikki yhteystiedot"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Haetaan..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Löytyi yli <xliff:g id="COUNT">%d</xliff:g> yhteystietoa."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Ei kontakteja"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> löytyi</item>
+ <item quantity="one">1 löytyi</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Pikayhteys henkilöön <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Ei nimeä)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Usein käytetyt"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Näytä yhteystieto"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Kaikki kontaktit puhelinnumeroineen"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Näytä päivitykset"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nimi"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Lempinimi"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nimi"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Nimen etuliite"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Toinen nimi"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Nimen jälkiliite"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nimen ääntämistapa"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Toisen nimen ääntämistapa"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Puhelin"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Sähköposti"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Osoite"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Pikaviestitili"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisaatio"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Suhde"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Tekstiviesti"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Osoite"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Yritys"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Nimi"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Muistiinpanot"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Sivusto"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Lähetä sähköpostia kotiosoitteeseen"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Lähetä sähköpostia mobiiliosoitteeseen"</string>
+ <string name="email_work" msgid="2807430017302722689">"Lähetä sähköpostia työosoitteeseen"</string>
+ <string name="email_other" msgid="3454004077967657109">"Sähköposti"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Lähetä sähköpostia osoitteeseen <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Sähköposti"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Katuosoite"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Postilokero"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Kaupunginosa"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Kaupunki"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Lääni"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Postinumero"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Maa"</string>
+ <string name="map_home" msgid="1243547733423343982">"Näytä kotiosoite"</string>
+ <string name="map_work" msgid="1360474076921878088">"Näytä työosoite"</string>
+ <string name="map_other" msgid="3817820803587012641">"Näytä osoite"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Näytä osoite <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Keskustele AIM:n avulla"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Keskustele Windows Liven avulla"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Keskustele Yahoon avulla"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Keskustele Skypen avulla"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Keskustele QQ:n avulla"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Keskustele Google Talkin avulla"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Keskustele ICQ:n avulla"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Keskustele Jabberin avulla"</string>
+ <string name="chat" msgid="9025361898797412245">"Pikaviesti"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"poista"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Laajenna tai tiivistä nimikentät"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Kaikki yhteystiedot"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Tähdelliset"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Muokkaa"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Yhteystiedot"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Kaikki muut yhteystiedot"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Kaikki yhteystiedot"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Poista synkronointiryhmä"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Lisää synkronointiryhmä"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Lisää ryhmiä…"</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Ryhmän <xliff:g id="GROUP">%s</xliff:g> poistaminen synkronoinnista lopettaa myös ryhmittelemättömien yhteystietojen synkronoinnin."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Tallennetaan näyttövalintoja…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Valmis"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Peruuta"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Tuo SIM-kortilta"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Peruuta kohteen <xliff:g id="FILENAME">%s</xliff:g> tuonti?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Peruuta kohteen <xliff:g id="FILENAME">%s</xliff:g> vienti?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCardin tuonnin/viennin peruutus epäonn."</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Tuntematon virhe."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Tiedostoa \"<xliff:g id="FILE_NAME">%s</xliff:g>\" ei voi avata: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Vientiohjelman käynnistys epäonnistui: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Ei vietäviä yhteystietoja."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Virhe viennin aikana: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Tarvittava tiedostonimi on liian pitkä (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O-virhe"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Muisti ei riitä. Tiedosto voi olla liian suuri."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"vCardia ei voi jäsentää odottamattomasta syystä."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Muotoa ei tueta."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Annettujen vCard-tiedostojen sisällönkuvaustietojen noutaminen epäonnistui."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Ainakin yhden tiedoston tuominen epäonnistui (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Kohteen <xliff:g id="FILENAME">%s</xliff:g> vienti valmis."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Kohteen <xliff:g id="FILENAME">%s</xliff:g> vienti peruutettu."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Viedään yhteystietoja"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Tietokannan tietojen hakeminen epäonnistui."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Ei vietäviä yhteystietoja. Jos puhelimessasi on yhteystietoja, tietojen tarjoaja on saattanut estää niiden viemisen puhelimen ulkopuolelle."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard-luonti ei käynnistynyt oikein."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Vieminen epäonnistui"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Yhteystietoja ei viety.\nSyy: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Tuodaan <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard-tietojen luku epäonnistui."</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard-tietojen lukeminen peruttu"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCardin <xliff:g id="FILENAME">%s</xliff:g> tuonti valmis"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Kohteen <xliff:g id="FILENAME">%s</xliff:g> tuonti peruttu"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> tuodaan pian."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Tiedosto tuodaan pian."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard-tuontipyyntö hylättiin. Yritä myöhemmin uudelleen."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> viedään pian."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard-vientipyyntö hylättiin. Yritä myöhemmin uudelleen."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"yhteystieto"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Lisätään vCard-tietojen välimuistiversiot paikalliseen väliaikaistallennustilaan. Tuonti alkaa pian."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard-tietojen tuominen epäonnistui."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontakti saatu (NFC)"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Vie yhteystietoja?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Vie välimuistiin"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Tuodaan <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Asetukset"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Jaa näkyvät yhteystiedot"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Tuo/Vie yhteystietoja"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Tuo yhteystietoja"</string>
+ <string name="share_error" msgid="948429331673358107">"Yhteystieto ei jaettavissa"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Haku"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Näytettävät yhteystiedot"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Näytettävät yhteystiedot"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Suosikit"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Ei yhteystietoja."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Tyhjennä usein käytetyt"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Valitse SIM-kortti"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Tuo/Vie"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Estetyt numerot"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"lähteestä: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> lähteestä: <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Tyhjennä haku"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index bb9a26e..79d1c58 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Définir par défaut"</string>
<string name="clear_default" msgid="7193185801596678067">"Effacer les valeurs par défaut"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Texte copié."</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Annuler les modifications et quitter le mode d\'édition?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Supprimer les modifications?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Ignorer"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Continuer les modifications"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Annuler"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Rechercher dans les contacts"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Supprimer les contacts"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"À propos"</string>
<string name="send_message" msgid="8938418965550543196">"Envoyer un message"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Création d\'une copie personnelle…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Hier"</string>
<string name="tomorrow" msgid="6241969467795308581">"Demain"</string>
<string name="today" msgid="8041090779381781781">"Aujourd\'hui"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Aujourd\'hui à <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Messages"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organisez votre liste"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Éliminez les doublons et groupez les contacts par étiquette"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Texte copié."</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copier dans le presse-papiers"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Appeler le <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Appeler le numéro de téléphone du domicile"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Appeler le numéro de téléphone mobile"</string>
+ <string name="call_work" msgid="5328785911463744028">"Appeler le numéro de téléphone professionnel"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Appeler le numéro de télécopie professionnel"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Appeler le numéro de télécopie du domicile"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Appeler le téléavertisseur"</string>
+ <string name="call_other" msgid="8563753966926932052">"Appeler"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Appeler le numéro de rappel"</string>
+ <string name="call_car" msgid="3280537320306436445">"Appeler le numéro de télphone de la voiture"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Appeler le numéro de téléphone principal de l\'entreprise"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Appeler le numéro de téléphone RNIS"</string>
+ <string name="call_main" msgid="6082900571803441339">"Appeler le numéro de téléphone principal"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Appeler le numéro de télécopie"</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 le numéro TTY/TDD (malentendants)"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Appeler le numéro de téléphone mobile professionnel"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Appeler le téléavertisseur professionnel"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Appeler le <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Appeler le numéro de téléphone MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Envoyer un SMS au <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Envoyer un SMS au numéro de téléphone du domicile"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Envoyer un SMS au numéro de téléphone mobile"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Envoyer un SMS au numéro de téléphone professionnel"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Envoyer un SMS au numéro de télécopie professionnel"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Envoyer un SMS au numéro de télécopie du domicile"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Envoyer un SMS au téléavertisseur"</string>
+ <string name="sms_other" msgid="806127844607642331">"Texte"</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 au numéro de téléphone de la voiture"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Envoyer un SMS au numéro de téléphone principal de l\'entreprise"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Envoyer un SMS au numéro de téléphone RNIS"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Envoyer un SMS au numéro de téléphone principal"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Envoyer un SMS au numéro de télécopie"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Envoyer un SMS par signal radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Envoyer un SMS par télex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Envoyer un SMS au numéro TTY/TDD (malentendants)"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Envoyer un SMS au numéro de téléphone mobile professionnel"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Envoyer un SMS au téléavertisseur professionnel"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Envoyer un SMS au <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Envoyer un SMS au numéro de téléph MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Effacer les contacts fréquents?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Suppression des contacts fréquents…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Disponible"</string>
+ <string name="status_away" msgid="1838861100379804730">"Absent"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Occupé(e)"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contacts"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Autre"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Répertoire"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Tous les contacts"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Recherche en cours..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Plus de <xliff:g id="COUNT">%d</xliff:g> contacts ont été trouvés."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Aucun contact"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> résultat</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> résultats</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Lien rapide vers <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Sans nom)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Contacts fréquents"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Afficher le contact"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Tous les contacts disposant d\'un numéro de téléphone"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Afficher les mises à jour"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nom"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Pseudonyme"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nom"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Préfixe du nom"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Deuxième prénom"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Suffixe du nom"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nom phonétique"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Deuxième prénom phonétique"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Téléphone"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Adresse de courriel :"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adresse"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Messagerie instantanée"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relation"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Message texte"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adresse"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Entreprise"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titre"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Remarques"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Site Web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Envoyer un courriel au domicile"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Envoyer un courriel sur le mobile"</string>
+ <string name="email_work" msgid="2807430017302722689">"Envoyer un courriel au bureau"</string>
+ <string name="email_other" msgid="3454004077967657109">"Adresse de courriel :"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Envoyer un courriel à <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Adresse de courriel :"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Rue"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Case postale"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Quartier"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Ville"</string>
+ <string name="postal_region" msgid="6045263193478437672">"État/province"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Code postal"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Pays"</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="3817820803587012641">"Afficher l\'adresse"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Afficher l\'adresse <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Clavarder via AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Clavarder via Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Clavarder via Yahoo!"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Clavarder via Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Clavarder via QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Clavarder via Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Clavarder via ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Clavarder via Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Clavardage"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"suppr"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Développer ou réduire les champs de nom"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Tous les contacts"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Marqués d\'une étoile"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personnaliser"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"contact"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Tous les autres contacts"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Tous les contacts"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Le retrait du groupe \"<xliff:g id="GROUP">%s</xliff:g>\" de la synchronisation entraîne également le retrait des contacts n\'appartenant à aucun groupe."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Enregistrement des options d\'affichage en cours…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Terminé"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Annuler"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importer depuis la carte SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Annuler l\'importation du fichier <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Annuler l\'exportation du fichier <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Impossible annuler import./export. vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Erreur inconnue."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Impossible d\'ouvrir le fichier <xliff:g id="FILE_NAME">%s</xliff:g> pour la raison suivante : <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Impossible de démarrer le programme d\'exportation pour la raison suivante : <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Aucun contact ne peut être exporté."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Une erreur s\'est produite lors de l\'exportation : <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Le nom de fichier requis est trop long (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Erreur d\'E/S."</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Mémoire insuffisante. Le fichier est peut-être trop volumineux."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Impossible d\'analyser le fichier vCard pour une raison inattendue."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Le format n\'est pas compatible."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Impossible de collecter des métadonnées contenues dans le ou les fichiers vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Impossible d\'importer un ou plusieurs fichiers (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Exportation du fichier <xliff:g id="FILENAME">%s</xliff:g> terminée"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exportation du fichier <xliff:g id="FILENAME">%s</xliff:g> annulée"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportation des données des contacts en cours"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Impossible d\'obtenir les informations concernant la base de données."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Aucun contact ne peut être exporté. Si des contacts sont enregistrés sur votre téléphone, il est possible qu\'un fournisseur de données n\'autorise pas l\'exportation de contacts vers un autre appareil."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Le système de composition vCard n\'a pas démarré correctement."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Échec exportation"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Les données du contact n\'ont pas été exportées.\nMotif : <xliff:g id="FAIL_REASON">%s</xliff:g>."</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importation (<xliff:g id="NAME">%s</xliff:g>)"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Impossible de lire les données vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Lecture des données vCard annulée"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Le fichier vCard <xliff:g id="FILENAME">%s</xliff:g> a bien été importé"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importation du fichier <xliff:g id="FILENAME">%s</xliff:g> annulée"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Le fichier <xliff:g id="FILENAME">%s</xliff:g> va bientôt être importé."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Le fichier va bientôt être importé."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"La demande d\'importation du fichier vCard a été rejetée. Veuillez réessayer plus tard."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Le fichier <xliff:g id="FILENAME">%s</xliff:g> va bientôt être exporté."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"La demande d\'exportation du fichier vCard a été rejetée. Veuillez réessayer plus tard."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contact"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Mise en cache des fichiers vCard dans l\'espace de stockage temporaire local. L\'importation va bientôt démarrer."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Impossible d\'importer le fichier vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contact reçu via NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exporter les contacts?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Mise en cache…"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importation <xliff:g id="CURRENT_NUMBER">%s</xliff:g> sur <xliff:g id="TOTAL_NUMBER">%s</xliff:g> (<xliff:g id="NAME">%s</xliff:g>)"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Paramètres"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Partager les contacts visibles"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importer/Exporter des contacts"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Téléverser des contacts"</string>
+ <string name="share_error" msgid="948429331673358107">"Impossible de partager ce contact."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Rechercher"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contacts à afficher"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contacts à afficher"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoris"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Aucun contact"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Effacer les contacts fréquents"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Sélectionner une carte SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importer/Exporter"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Numéros bloqués"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Effacer les termes de recherche"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index de8df9c..2d48423 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Définir par défaut"</string>
<string name="clear_default" msgid="7193185801596678067">"Effacer les valeurs par défaut"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Texte copié"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Supprimer les modifications et quitter le mode d\'édition ?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Ignorer les modifications ?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Supprimer"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Poursuivre les modifications"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Annuler"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Rechercher des contacts"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Supprimer les contacts"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"À propos de"</string>
<string name="send_message" msgid="8938418965550543196">"Envoyer le message"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Création d\'une copie personnelle…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Hier"</string>
<string name="tomorrow" msgid="6241969467795308581">"Demain"</string>
<string name="today" msgid="8041090779381781781">"Aujourd\'hui"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Aujourd\'hui, <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Messages"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organiser votre liste"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Nettoyer les doublons et regrouper les contacts par libellé"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Texte copié"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copier dans le presse-papiers"</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 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="8563753966926932052">"Appeler"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Appeler numéro de rappel"</string>
+ <string name="call_car" msgid="3280537320306436445">"Appeler voiture"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Appeler entreprise (principal)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Appeler numéro RNIS"</string>
+ <string name="call_main" msgid="6082900571803441339">"Appeler numéro principal"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Appeler numéro de 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 mobile bureau"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Appeler téléavertisseur bureau"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Envoyer un SMS"</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 à entreprise (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="3888842199855843152">"Envoyer un SMS à ce 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 SMS à <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Envoyer un MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Effacer les contacts fréquents ?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Suppression des contacts fréquents"</string>
+ <string name="status_available" msgid="5586870015822828392">"Disponible"</string>
+ <string name="status_away" msgid="1838861100379804730">"Absent"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Occupé"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contacts"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Autre"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Annuaire"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Tous les contacts"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Recherche…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Plus de <xliff:g id="COUNT">%d</xliff:g> résultats trouvés."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Aucun contact"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> contact trouvé</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> contacts trouvés</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Liens rapides vers <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Sans nom)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Contacts fréquents"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Afficher le contact"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Tous les contacts disposant d\'un numéro de téléphone"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Afficher mises à jour"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nom"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Pseudo"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nom"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Titre"</string>
+ <string name="name_middle" msgid="8467433655992690326">"2e prénom"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Suffixe"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nom phonétique"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Phonétique 2e prénom"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Téléphone"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mail"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adresse"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Chat"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relation"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"SMS"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adresse"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Entreprise"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titre"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notes"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Site Web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Env. e-mail domicile"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Envoyer un e-mail sur le mobile"</string>
+ <string name="email_work" msgid="2807430017302722689">"Env. e-mail bureau"</string>
+ <string name="email_other" msgid="3454004077967657109">"Envoyer un e-mail"</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="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="map_home" msgid="1243547733423343982">"Afficher adresse perso"</string>
+ <string name="map_work" msgid="1360474076921878088">"Afficher adresse prof."</string>
+ <string name="map_other" msgid="3817820803587012641">"Afficher l\'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">"Chatter"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"supprimer"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Développer ou réduire les champs de nom"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Tous les contacts"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Contacts favoris"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personnaliser"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contact"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Tous les autres contacts"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Tous les contacts"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Le retrait de \"<xliff:g id="GROUP">%s</xliff:g>\" de la synchronisation entraînera également le retrait des contacts n\'appartenant à aucun groupe."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Enregistrement des options d\'affichage..."</string>
+ <string name="menu_done" msgid="796017761764190697">"OK"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Annuler"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importer à partir de la carte SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Annuler l\'importation de \"<xliff:g id="FILENAME">%s</xliff:g>\" ?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Annuler l\'exportation de \"<xliff:g id="FILENAME">%s</xliff:g>\" ?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Impossible annuler import./export. vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Erreur inconnue."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Impossible d\'ouvrir \"<xliff:g id="FILE_NAME">%s</xliff:g>\" pour la raison suivante : <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Impossible de démarrer le programme d\'exportation : \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Aucun contact ne peut être exporté."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Une erreur s\'est produite lors de l\'exportation : \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Le nom de fichier requis est trop long (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Erreur d\'E/S."</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Mémoire insuffisante. Le fichier est peut-être trop volumineux."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Impossible d\'analyser le fichier vCard pour une raison inattendue."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Ce format n\'est pas compatible."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Impossible de collecter des métadonnées contenues dans le ou les fichiers vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Impossible d\'importer un ou plusieurs fichiers (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Exportation de \"<xliff:g id="FILENAME">%s</xliff:g>\" terminée"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exportation de \"<xliff:g id="FILENAME">%s</xliff:g>\" annulée"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportation des données des contacts"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Impossible d\'obtenir les informations concernant la base de données."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Aucun contact ne peut être exporté. Si des contacts sont enregistrés sur votre téléphone, il est possible qu\'un fournisseur de données n\'autorise pas l\'exportation de contacts vers un autre appareil."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Le système de composition vCard n\'a pas démarré correctement."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Échec exportation"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Les données du contact n\'ont pas été exportées.\nMotif : \"<xliff:g id="FAIL_REASON">%s</xliff:g>\"."</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importation en cours : <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Impossible de lire les données vCard."</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Lecture des données vCard annulée"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Fichier vCard <xliff:g id="FILENAME">%s</xliff:g> importé"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importation de \"<xliff:g id="FILENAME">%s</xliff:g>\" annulée"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Importation du fichier <xliff:g id="FILENAME">%s</xliff:g> imminente"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Le fichier va bientôt être importé."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"La demande d\'importation du fichier vCard a été rejetée. Veuillez réessayer ultérieurement."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Exportation du fichier <xliff:g id="FILENAME">%s</xliff:g> imminente"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"La demande d\'exportation du fichier vCard a été rejetée. Veuillez réessayer ultérieurement."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contact"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Mise en cache des fichiers vCard dans l\'espace de stockage temporaire local. L\'importation va bientôt démarrer."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Impossible d\'importer le fichier vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contact reçu via NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exporter contacts ?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Mise en cache…"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importation en cours <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g> : <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Paramètres"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Partager les contacts visibles"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Import/Export contacts"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importer des contacts"</string>
+ <string name="share_error" msgid="948429331673358107">"Impossible de partager ce contact."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Rechercher"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contacts à afficher"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contacts à afficher"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoris"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Aucun contact"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Effacer les contacts fréquents"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Sélectionner une carte SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importer/Exporter"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Numéros bloqués"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Effacer la recherche"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index fca4cc1..583eb7f 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Definir como predeterminado"</string>
<string name="clear_default" msgid="7193185801596678067">"Borrar valores predeterminados"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Queres descartar os teus cambios e deixar de editar?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Queres descartar os cambios?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Descartar"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Seguir editando"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Cancelar"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Busca nos contactos"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Eliminar contactos"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Acerca de"</string>
<string name="send_message" msgid="8938418965550543196">"Enviar mensaxe"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Creando unha copia persoal..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Onte"</string>
<string name="tomorrow" msgid="6241969467795308581">"Mañá"</string>
<string name="today" msgid="8041090779381781781">"Hoxe"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Hoxe ás <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mensaxes"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organiza a túa lista"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Elimina os duplicados e agrupa os contactos por etiqueta"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copiar no portapapeis"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Chamar ao <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Chamar á casa"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Chamar ao móbil"</string>
+ <string name="call_work" msgid="5328785911463744028">"Chamar ao traballo"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Chamar ao número de fax do traballo"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Chamar ao número de fax da casa"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Chamar ao busca"</string>
+ <string name="call_other" msgid="8563753966926932052">"Chamar"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Chamar ao número de devolución de chamada"</string>
+ <string name="call_car" msgid="3280537320306436445">"Chamar ao coche"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Chamar ao número principal da empresa"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Chamar ao número de RDSI"</string>
+ <string name="call_main" msgid="6082900571803441339">"Chamar ao número principal"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Chamar ao fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Chamar á radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Chamar ao télex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Chamar ao número de TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Chamar ao móbil do traballo"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Chamar ao busca do traballo"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Chamar a <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Chamar ao número de teléfono de MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Enviar unha mensaxe a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Enviar unha mensaxe á casa"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Enviar unha mensaxe ao teléfono móbil"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Enviar unha mensaxe ao traballo"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Enviar unha mensaxe ao fax do traballo"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Enviar unha mensaxe ao fax da casa"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Enviar unha mensaxe ao busca"</string>
+ <string name="sms_other" msgid="806127844607642331">"Enviar unha mensaxe"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Enviar unha mensaxe ao número de devolución da chamada"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Enviar unha mensaxe ao coche"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Enviar unha mensaxe ao teléfono principal da empresa"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Enviar unha mensaxe ao teléfono de RDSI"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Enviar unha mensaxe ao teléfono principal"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Enviar unha mensaxe ao fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Enviar unha mensaxe á radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Enviar unha mensaxe ao télex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Enviar unha mensaxe ao TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Enviar unha mensaxe ao móbil do traballo"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Enviar unha mensaxe ao busca do traballo"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Enviar unha mensaxe a <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Enviar unha mensaxe ao MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Borrar contactados con frecuencia?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Borrando contactados frecuencia..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Dispoñible"</string>
+ <string name="status_away" msgid="1838861100379804730">"Ausente"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Ocupado"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contactos"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Outro"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Directorio"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Todos os contactos"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Buscando..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Encontráronse máis de <xliff:g id="COUNT">%d</xliff:g> contactos."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Non hai contactos"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> contactos encontrados</item>
+ <item quantity="one">Un contacto encontrado</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Contacto rápido para <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Sen nome)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Contactados frecuentemente"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Ver contacto"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Todos os contactos con números de teléfono"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Ver actualizacións"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nome"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Alcume"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nome"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Tratamento do nome"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Segundo nome"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Información profesional do nome"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nome fonético"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Segundo nome fonético"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Teléfono"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Correo electrónico"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Enderezo"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"MI"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organización"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relación"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Mensaxe de texto"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Enderezo"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Cargo"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notas"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Sitio web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Enviar correo electrónico á casa"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Enviar correo electrónico ao móbil"</string>
+ <string name="email_work" msgid="2807430017302722689">"Enviar correo electrónico ao traballo"</string>
+ <string name="email_other" msgid="3454004077967657109">"Correo electrónico"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Enviar correo electrónico a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Correo electrónico"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Rúa"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Apartado de correos"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Barrio"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Cidade"</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="map_home" msgid="1243547733423343982">"Ver enderezo da casa"</string>
+ <string name="map_work" msgid="1360474076921878088">"Ver enderezo do traballo"</string>
+ <string name="map_other" msgid="3817820803587012641">"Ver enderezo"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Ver enderezo <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">"Chatear"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"eliminar"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Amplía ou contrae os campos do nome"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Todos os contactos"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Marcados con estrela"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personalizar"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contacto"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Todos os demais contactos"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Todos os contactos"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Eliminar grupo de sincronización"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Engadir grupo de sincronización"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Máis grupos..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Se eliminas \"<xliff:g id="GROUP">%s</xliff:g>\" da sincronización, tamén eliminarás os contactos non agrupados da sincronización."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Gardando opcións de visualización..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Feito"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Cancelar"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importar da tarxeta SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Queres cancelar importación de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Queres cancelar a exportación de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Imposible cancelar import./export. vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Erro descoñecido."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Non se puido abrir \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Non se puido iniciar o exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Non hai ningún contacto exportable."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Produciuse un erro durante a exportación: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"O nome do ficheiro necesario é demasiado longo (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Erro de E/S"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Non hai memoria suficiente. É posible que o ficheiro sexa demasiado grande."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Non se puido analizar o ficheiro vCard debido a un motivo inesperado."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"O formato non é compatible."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Non se puido recoller a información meta de determinados ficheiros vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Non se puideron importar un ou máis ficheiros (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Finalizou a exportación de <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Cancelouse a exportación de <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportando datos de contactos"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Non se puido obter a información da base de datos."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Non hai ningún contacto exportable. Se tes contactos no teléfono, é posible que algúns provedores de datos non permitan a exportación dos contactos desde o teléfono."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"O redactor de vCard non se iniciou correctamente."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Imposible exportar"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Non se exportaron os datos dos contactos.\n Motivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importando <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Non se puideron ler os datos de vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Lectura dos datos de vCard cancelada"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Importación de <xliff:g id="FILENAME">%s</xliff:g> de vCard finalizada"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importación de <xliff:g id="FILENAME">%s</xliff:g> cancelada"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> importarase en breve."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"O ficheiro importarase en breve."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Rexeitouse a solicitude de importación do ficheiro vCard. Téntao de novo máis tarde."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> exportarase en breve."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Rexeitouse a solicitude de exportación de vCard. Téntao de novo máis tarde."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contacto"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Estanse almacenando as vCard na memoria caché do almacenamento temporal local. A importación real comezará en breve."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Non se puido importar o ficheiro vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contacto recibido por NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Queres exportar contactos?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Almacenando na caché"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importando <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Configuración"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Compartir contactos visibles"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importar/exportar contactos"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importar contactos"</string>
+ <string name="share_error" msgid="948429331673358107">"Non se pode compartir este contacto."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Buscar"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contactos para mostrar"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contactos para mostrar"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Ningún contacto"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Borrar frecuentes"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Seleccionar tarxeta SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importar/exportar"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Números bloqueados"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"a través de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> a través de <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Borrar busca"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index 3d3fcc5..dc81488 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"ડિફોલ્ટ સેટ કરો"</string>
<string name="clear_default" msgid="7193185801596678067">"ડિફોલ્ટ સાફ કરો"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"ટેક્સ્ટ કૉપિ કર્યો"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"તમારા ફેરફારોને નિકાળીને સંપાદન છોડી દઈએ?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"ફેરફારો નિકાળીએ?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"નિકાળો"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"સંપાદન ચાલુ રાખો"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"રદ કરો"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"સંપર્કો શોધો"</string>
<string name="title_edit_group" msgid="8602752287270586734">"સંપર્કો દૂર કરો"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"વિશે"</string>
<string name="send_message" msgid="8938418965550543196">"સંદેશ મોકલો"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"વ્યક્તિગત કૉપિ બનાવી રહ્યાં છે…"</string>
- <string name="yesterday" msgid="6840858548955018569">"ગઈ કાલે"</string>
<string name="tomorrow" msgid="6241969467795308581">"આવતીકાલે"</string>
<string name="today" msgid="8041090779381781781">"આજે"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"<xliff:g id="TIME_INTERVAL">%s</xliff:g> વાગ્યે આજે"</string>
@@ -342,4 +341,506 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"સંદેશા"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"તમારી સૂચિ ગોઠવો"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"ડુપ્લિકેટ્સ સાફ કરો અને લેબલ દ્વારા સંપર્કોને જૂથબદ્ધ કરો"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"ટેક્સ્ટ કૉપિ કર્યો"</string>
+ <string name="copy_text" msgid="3257145021583508761">"ક્લિપબોર્ડ પર કૉપિ કરો"</string>
+ <!-- no translation found for call_custom (7756571794763171802) -->
+ <skip />
+ <!-- no translation found for call_home (1990519474420545392) -->
+ <skip />
+ <!-- no translation found for call_mobile (7502236805487609178) -->
+ <skip />
+ <!-- no translation found for call_work (5328785911463744028) -->
+ <skip />
+ <!-- no translation found for call_fax_work (7467763592359059243) -->
+ <skip />
+ <!-- no translation found for call_fax_home (8342175628887571876) -->
+ <skip />
+ <!-- no translation found for call_pager (9003902812293983281) -->
+ <skip />
+ <!-- no translation found for call_other (8563753966926932052) -->
+ <skip />
+ <!-- no translation found for call_callback (1910165691349426858) -->
+ <skip />
+ <!-- no translation found for call_car (3280537320306436445) -->
+ <skip />
+ <!-- no translation found for call_company_main (6105120947138711257) -->
+ <skip />
+ <!-- no translation found for call_isdn (1541590690193403411) -->
+ <skip />
+ <!-- no translation found for call_main (6082900571803441339) -->
+ <skip />
+ <!-- no translation found for call_other_fax (5745314124619636674) -->
+ <skip />
+ <!-- no translation found for call_radio (8296755876398357063) -->
+ <skip />
+ <!-- no translation found for call_telex (2223170774548648114) -->
+ <skip />
+ <!-- no translation found for call_tty_tdd (8951266948204379604) -->
+ <skip />
+ <!-- no translation found for call_work_mobile (8707874281430105394) -->
+ <skip />
+ <!-- no translation found for call_work_pager (3419348514157949008) -->
+ <skip />
+ <!-- no translation found for call_assistant (2141641383068514308) -->
+ <skip />
+ <!-- no translation found for call_mms (6274041545876221437) -->
+ <skip />
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <!-- no translation found for sms_custom (5932736853732191825) -->
+ <skip />
+ <!-- no translation found for sms_home (7524332261493162995) -->
+ <skip />
+ <!-- no translation found for sms_mobile (5200107250451030769) -->
+ <skip />
+ <!-- no translation found for sms_work (2269624156655267740) -->
+ <skip />
+ <!-- no translation found for sms_fax_work (8028189067816907075) -->
+ <skip />
+ <!-- no translation found for sms_fax_home (9204042076306809634) -->
+ <skip />
+ <!-- no translation found for sms_pager (7730404569637015192) -->
+ <skip />
+ <!-- no translation found for sms_other (806127844607642331) -->
+ <skip />
+ <!-- no translation found for sms_callback (5004824430094288752) -->
+ <skip />
+ <!-- no translation found for sms_car (7444227058437359641) -->
+ <skip />
+ <!-- no translation found for sms_company_main (118970873419678087) -->
+ <skip />
+ <!-- no translation found for sms_isdn (8153785037515047845) -->
+ <skip />
+ <!-- no translation found for sms_main (8621625784504541679) -->
+ <skip />
+ <!-- no translation found for sms_other_fax (3888842199855843152) -->
+ <skip />
+ <!-- no translation found for sms_radio (3329166673433967820) -->
+ <skip />
+ <!-- no translation found for sms_telex (9034802430065267848) -->
+ <skip />
+ <!-- no translation found for sms_tty_tdd (6782284969132531532) -->
+ <skip />
+ <!-- no translation found for sms_work_mobile (2459939960512702560) -->
+ <skip />
+ <!-- no translation found for sms_work_pager (5566924423316960597) -->
+ <skip />
+ <!-- no translation found for sms_assistant (2773424339923116234) -->
+ <skip />
+ <!-- no translation found for sms_mms (4069352461380762677) -->
+ <skip />
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation_title (766292372438450432) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <!-- no translation found for clearFrequentsProgress_title (5157001637482794212) -->
+ <skip />
+ <!-- no translation found for status_available (5586870015822828392) -->
+ <skip />
+ <!-- no translation found for status_away (1838861100379804730) -->
+ <skip />
+ <!-- no translation found for status_busy (9147992455450257136) -->
+ <skip />
+ <string name="contactsList" msgid="8661624236494819731">"સંપર્કો"</string>
+ <!-- no translation found for local_invisible_directory (6046691709127661065) -->
+ <skip />
+ <!-- no translation found for directory_search_label (1887759056597975053) -->
+ <skip />
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <!-- no translation found for local_search_label (2551177578246113614) -->
+ <skip />
+ <string name="search_results_searching" msgid="3984833028938569930">"શોધી રહ્યું છે..."</string>
+ <!-- no translation found for foundTooManyContacts (5163335650920020220) -->
+ <skip />
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"સંપર્કો નથી"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> મળ્યાં</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> મળ્યાં</item>
+ </plurals>
+ <!-- no translation found for description_quick_contact_for (6737516415168327789) -->
+ <skip />
+ <!-- no translation found for missing_name (8745511583852904385) -->
+ <skip />
+ <!-- no translation found for favoritesFrequentContacted (6184232487472425690) -->
+ <skip />
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"સંપર્ક જુઓ"</string>
+ <!-- no translation found for list_filter_phones (735313795643493365) -->
+ <skip />
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <!-- no translation found for view_updates_from_group (1782685984905600034) -->
+ <skip />
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <!-- no translation found for nameLabelsGroup (2034640839640477827) -->
+ <skip />
+ <!-- no translation found for nicknameLabelsGroup (2891682101053358010) -->
+ <skip />
+ <!-- no translation found for full_name (6602579550613988977) -->
+ <skip />
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <!-- no translation found for name_prefix (59756378548779822) -->
+ <skip />
+ <!-- no translation found for name_middle (8467433655992690326) -->
+ <skip />
+ <!-- no translation found for name_suffix (3855278445375651441) -->
+ <skip />
+ <!-- no translation found for name_phonetic (4259595234312430484) -->
+ <skip />
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <!-- no translation found for name_phonetic_middle (8643721493320405200) -->
+ <skip />
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <!-- no translation found for phoneLabelsGroup (6468091477851199285) -->
+ <skip />
+ <!-- no translation found for emailLabelsGroup (8389931313045344406) -->
+ <skip />
+ <!-- no translation found for postalLabelsGroup (3487738141112589324) -->
+ <skip />
+ <!-- no translation found for imLabelsGroup (3898238486262614027) -->
+ <skip />
+ <!-- no translation found for organizationLabelsGroup (2478611760751832035) -->
+ <skip />
+ <!-- no translation found for relationLabelsGroup (1854373894284572781) -->
+ <skip />
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <!-- no translation found for sms (1756857139634224222) -->
+ <skip />
+ <!-- no translation found for postal_address (8765560217149624536) -->
+ <skip />
+ <!-- no translation found for ghostData_company (5414421120553765775) -->
+ <skip />
+ <!-- no translation found for ghostData_title (7496735200318496110) -->
+ <skip />
+ <!-- no translation found for label_notes (8337354953278341042) -->
+ <skip />
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <!-- no translation found for websiteLabelsGroup (4202998982804009261) -->
+ <skip />
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <!-- no translation found for email_home (8573740658148184279) -->
+ <skip />
+ <!-- no translation found for email_mobile (2042889209787989814) -->
+ <skip />
+ <!-- no translation found for email_work (2807430017302722689) -->
+ <skip />
+ <!-- no translation found for email_other (3454004077967657109) -->
+ <skip />
+ <!-- no translation found for email_custom (7548003991586214105) -->
+ <skip />
+ <!-- no translation found for email (5668400997660065897) -->
+ <skip />
+ <!-- no translation found for postal_street (8133143961580058972) -->
+ <skip />
+ <!-- no translation found for postal_pobox (4431938829180269821) -->
+ <skip />
+ <!-- no translation found for postal_neighborhood (1450783874558956739) -->
+ <skip />
+ <!-- no translation found for postal_city (6597491300084895548) -->
+ <skip />
+ <!-- no translation found for postal_region (6045263193478437672) -->
+ <skip />
+ <!-- no translation found for postal_postcode (572136414136673751) -->
+ <skip />
+ <!-- no translation found for postal_country (7638264508416368690) -->
+ <skip />
+ <!-- no translation found for map_home (1243547733423343982) -->
+ <skip />
+ <!-- no translation found for map_work (1360474076921878088) -->
+ <skip />
+ <!-- no translation found for map_other (3817820803587012641) -->
+ <skip />
+ <!-- no translation found for map_custom (6184363799976265281) -->
+ <skip />
+ <!-- no translation found for chat_aim (2588492205291249142) -->
+ <skip />
+ <!-- no translation found for chat_msn (8041633440091073484) -->
+ <skip />
+ <!-- no translation found for chat_yahoo (6629211142719943666) -->
+ <skip />
+ <!-- no translation found for chat_skype (1210045020427480566) -->
+ <skip />
+ <!-- no translation found for chat_qq (4294637812847719693) -->
+ <skip />
+ <!-- no translation found for chat_gtalk (981575737258117697) -->
+ <skip />
+ <!-- no translation found for chat_icq (8438405386153745775) -->
+ <skip />
+ <!-- no translation found for chat_jabber (7561444230307829609) -->
+ <skip />
+ <!-- no translation found for chat (9025361898797412245) -->
+ <skip />
+ <!-- no translation found for description_minus_button (6908099247930477551) -->
+ <skip />
+ <!-- no translation found for expand_collapse_name_fields_description (8682630859539604311) -->
+ <skip />
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <!-- no translation found for list_filter_all_accounts (8908683398914322369) -->
+ <skip />
+ <!-- no translation found for list_filter_all_starred (5031734941601931356) -->
+ <skip />
+ <!-- no translation found for list_filter_customize (4789963356004169321) -->
+ <skip />
+ <!-- no translation found for list_filter_single (5871400283515893087) -->
+ <skip />
+ <!-- no translation found for display_ungrouped (6885954210243119591) -->
+ <skip />
+ <!-- no translation found for display_all_contacts (2031647544742889505) -->
+ <skip />
+ <!-- no translation found for menu_sync_remove (3266725887008450161) -->
+ <skip />
+ <!-- no translation found for dialog_sync_add (8267045393119375803) -->
+ <skip />
+ <!-- no translation found for display_more_groups (2682547080423434170) -->
+ <skip />
+ <!-- no translation found for display_warn_remove_ungrouped (8872290721676651414) -->
+ <skip />
+ <!-- no translation found for savingDisplayGroups (2133152192716475939) -->
+ <skip />
+ <!-- no translation found for menu_done (796017761764190697) -->
+ <skip />
+ <!-- no translation found for menu_doNotSave (58593876893538465) -->
+ <skip />
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <!-- no translation found for import_from_sim (3859272228033941659) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <!-- no translation found for cancel_import_confirmation_message (3929951040347726757) -->
+ <skip />
+ <!-- no translation found for cancel_export_confirmation_message (1995462401949262638) -->
+ <skip />
+ <!-- no translation found for cancel_vcard_import_or_export_failed (6139900383366166706) -->
+ <skip />
+ <!-- no translation found for fail_reason_unknown (1714092345030570863) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_open_file (2067725459821997463) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_initialize_exporter (707260459259688510) -->
+ <skip />
+ <!-- no translation found for fail_reason_no_exportable_contact (8728506011371262065) -->
+ <skip />
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <!-- no translation found for fail_reason_error_occurred_during_export (3018855323913649063) -->
+ <skip />
+ <!-- no translation found for fail_reason_too_long_filename (3393764245254738333) -->
+ <skip />
+ <!-- no translation found for fail_reason_io_error (6748358842976073255) -->
+ <skip />
+ <!-- no translation found for fail_reason_low_memory_during_import (875222757734882898) -->
+ <skip />
+ <!-- no translation found for fail_reason_vcard_parse_error (888263542360355784) -->
+ <skip />
+ <!-- no translation found for fail_reason_not_supported (8219562769267148825) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_collect_vcard_meta_info (6427931733267328564) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title (4767045779458185251) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_canceled_title (2652222370493306887) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <!-- no translation found for composer_failed_to_get_database_infomation (1765944280846236723) -->
+ <skip />
+ <!-- no translation found for composer_has_no_exportable_contact (3296493229040294335) -->
+ <skip />
+ <!-- no translation found for composer_not_initialized (2321648986367005254) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_title (4892358112409576342) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_message (4938527850142003141) -->
+ <skip />
+ <!-- no translation found for importing_vcard_description (4245275224298571351) -->
+ <skip />
+ <!-- no translation found for reading_vcard_failed_title (4251647443358422855) -->
+ <skip />
+ <!-- no translation found for reading_vcard_canceled_title (1925216585981542019) -->
+ <skip />
+ <!-- no translation found for importing_vcard_finished_title (3341541727268747967) -->
+ <skip />
+ <!-- no translation found for importing_vcard_canceled_title (2147475978165599336) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message (2804911199145873396) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message_with_default_name (1022969530654129470) -->
+ <skip />
+ <!-- no translation found for vcard_import_request_rejected_message (2890471184508516011) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message (2210241345252081463) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <!-- no translation found for vcard_export_request_rejected_message (2844874826431327531) -->
+ <skip />
+ <!-- no translation found for vcard_unknown_filename (7171709890959915954) -->
+ <skip />
+ <!-- no translation found for caching_vcard_message (4926308675041506756) -->
+ <skip />
+ <!-- no translation found for vcard_import_failed (5223531255894842406) -->
+ <skip />
+ <!-- no translation found for nfc_vcard_file_name (2823095213265993609) -->
+ <skip />
+ <!-- no translation found for confirm_export_title (6834385377255286349) -->
+ <skip />
+ <!-- no translation found for caching_vcard_title (1226272312940516605) -->
+ <skip />
+ <!-- no translation found for progress_notifier_message (2311011466908220528) -->
+ <skip />
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"સેટિંગ્સ"</string>
+ <!-- no translation found for share_visible_contacts (890150378880783797) -->
+ <skip />
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <!-- no translation found for dialog_import_export (4360648034889921624) -->
+ <skip />
+ <!-- no translation found for dialog_import (2431698729761448759) -->
+ <skip />
+ <!-- no translation found for share_error (948429331673358107) -->
+ <skip />
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <!-- no translation found for menu_search (9147752853603483719) -->
+ <skip />
+ <!-- no translation found for menu_contacts_filter (2165153460860262501) -->
+ <skip />
+ <!-- no translation found for activity_title_contacts_filter (8275542497615516969) -->
+ <skip />
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <!-- no translation found for contactsFavoritesLabel (8417039765586853670) -->
+ <skip />
+ <!-- no translation found for listTotalAllContactsZero (5513001821794568211) -->
+ <skip />
+ <!-- no translation found for menu_clear_frequents (7688250191932838833) -->
+ <skip />
+ <!-- no translation found for menu_select_sim (3603578201960504010) -->
+ <skip />
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <!-- no translation found for menu_import_export (26217871113229507) -->
+ <skip />
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"અવરોધિત નંબરો"</string>
+ <!-- no translation found for contact_status_update_attribution (752179367353018597) -->
+ <skip />
+ <!-- no translation found for contact_status_update_attribution_with_date (7358045508107825068) -->
+ <skip />
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"શોધ સાફ કરો"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 9ee58ff..e327ac1 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"सामान्य सेट करें"</string>
<string name="clear_default" msgid="7193185801596678067">"सामान्य साफ़ करें"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"लेख की प्रतिलिपि बनाई गई"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"अपने बदलावों को ख़ारिज करें और संपादन से बाहर निकलें?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"क्या परिवर्तनों को छोड़ना चाहते हैं?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"अभी नहीं"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"संपादित करते रहें"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"रद्द करें"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"संपर्क खोजें"</string>
<string name="title_edit_group" msgid="8602752287270586734">"संपर्क निकालें"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"संक्षिप्त विवरण"</string>
<string name="send_message" msgid="8938418965550543196">"संदेश भेजें"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"एक व्यक्तिगत प्रतिलिपि बना रहा है…"</string>
- <string name="yesterday" msgid="6840858548955018569">"कल"</string>
<string name="tomorrow" msgid="6241969467795308581">"कल"</string>
<string name="today" msgid="8041090779381781781">"आज"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"आज <xliff:g id="TIME_INTERVAL">%s</xliff:g> बजे"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"संदेश"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"अपनी सूची व्यवस्थित करें"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"डुप्लिकेट और समूह संपर्कों को लेबल द्वारा साफ़ करें"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"लेख की प्रतिलिपि बनाई गई"</string>
+ <string name="copy_text" msgid="3257145021583508761">"क्लिपबोर्ड पर प्रतिलिपि बनाएं"</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="8563753966926932052">"कॉल करें"</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="5745314124619636674">"अन्य फ़ैक्स नंबर पर कॉल करें"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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">"कार्यस्थल फ़ैक्स नंबर पर SMS भेजें"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"घर के फ़ैक्स पर SMS भेजें"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"पेजर पर SMS भेजें"</string>
+ <string name="sms_other" msgid="806127844607642331">"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">"मुख्य फ़ोन नंबर पर SMS भेजें"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"इस फ़ैक्स नंबर पर 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 भेजें"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"अक्सर किए जाने वाले संपर्क साफ करें?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"अक्सर किए जाने वाले संपर्क साफ़ कर रहा है…"</string>
+ <string name="status_available" msgid="5586870015822828392">"उपलब्ध"</string>
+ <string name="status_away" msgid="1838861100379804730">"दूर"</string>
+ <string name="status_busy" msgid="9147992455450257136">"व्यस्त"</string>
+ <string name="contactsList" msgid="8661624236494819731">"संपर्क"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"अन्य"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"निर्देशिका"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"सभी संपर्क"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"खोज रहा है…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g> से अधिक मिले."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"कोई संपर्क नहीं"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> मिले</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> मिले</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> के लिए त्वरित संपर्क"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(कोई नाम नहीं)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"बार-बार संपर्क किया गया"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"संपर्क देखें"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"फ़ोन नंबरों वाले सभी संपर्क."</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"नई जानकारी देखें"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"नाम"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"प्रचलित नाम"</string>
+ <string name="full_name" msgid="6602579550613988977">"नाम"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"फ़ोनेटिक नाम"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"फ़ोनेटिक मध्य नाम"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"फ़ोन"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"ईमेल"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"पता"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"संगठन"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"संबंध"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"लेख संदेश"</string>
+ <string name="postal_address" msgid="8765560217149624536">"पता"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"कंपनी"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"शीर्षक"</string>
+ <string name="label_notes" msgid="8337354953278341042">"नोट"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"वेबसाइट"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"ईमेल भेजें"</string>
+ <string name="email_custom" msgid="7548003991586214105">"<xliff:g id="CUSTOM">%s</xliff:g> पर ईमेल भेजें"</string>
+ <string name="email" msgid="5668400997660065897">"ईमेल भेजें"</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="map_home" msgid="1243547733423343982">"घर का पता देखें"</string>
+ <string name="map_work" msgid="1360474076921878088">"कार्यस्थल का पता देखें"</string>
+ <string name="map_other" msgid="3817820803587012641">"पता देखें"</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="description_minus_button" msgid="6908099247930477551">"हटाएं"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"नाम फ़ील्ड विस्तृत या संक्षिप्त करें"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"सभी संपर्क"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"तारांकित"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"कस्टमाइज़ करें"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"संपर्क"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"अन्य सभी संपर्क"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"सभी संपर्क"</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_warn_remove_ungrouped" msgid="8872290721676651414">"\"<xliff:g id="GROUP">%s</xliff:g>\" को समन्वयन से निकालने से समन्वयन से सभी असमूहीकृत संपर्क भी निकल जाएंगे."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"प्रदर्शन विकल्प सहेज रहा है…"</string>
+ <string name="menu_done" msgid="796017761764190697">"पूर्ण"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"अभी नहीं"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"सिम कार्ड से आयात करें"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> का आयात रहने दें?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> का निर्यात रहने दें?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard आयात/निर्यात रद्द नहीं हो सका"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"अज्ञात त्रुटि."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" नहीं खोली जा सकी: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"निर्यातकर्ता प्रारंभ नहीं किया जा सका: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"कोई निर्यात-योग्य संपर्क नहीं है."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"निर्यात करते समय कोई त्रुटि आई: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"आवश्यक फ़ाइल नाम बहुत बड़ा है (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O त्रुटि"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"स्मृति पर्याप्त नहीं है. हो सकता है फ़ाइल बहुत बड़ी हो."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"किसी अप्रत्याशित कारण से vCard पार्स नहीं किया जा सका."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"प्रारूप समर्थित नहीं है."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"दी गई vCard फ़ाइल(फ़ाइलों) की मेटा जानकारी एकत्र नहीं की जा सकी."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"एक या अधिक फ़ाइलें आयात नहीं की जा सकीं (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> का निर्यात करना पूर्ण."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> को निर्यात करना रद्द किया गया."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"संपर्क डेटा निर्यात हो रहा है"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"डेटाबेस जानकारी नहीं मिल सकी."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"कोई भी निर्यात-योग्य संपर्क नहीं है. यदि आपके पास अपने फ़ोन पर संपर्क हों, तो हो सकता है कि कुछ डेटा प्रदाता संपर्कों को फ़ोन से निर्यात न करने दें."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard कंपोज़र ठीक से शुरू नहीं हुआ."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"निर्यात नहीं कर सका"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"संपर्क डेटा निर्यात नहीं किया गया था.\nकारण: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> आयात कर रहा है"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard डेटा नहीं पढ़ा जा सका"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard डेटा को पढ़ना रद्द किया गया"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g> आयात करना पूर्ण"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> को आयात करना रद्द किया गया"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> को जल्दी ही आयात किया जाएगा."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"फ़ाइल शीघ्र ही आयात की जाएगी."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard आयात अनुरोध अस्वीकार हो गया था. बाद में पुन: प्रयास करें."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> को जल्दी ही निर्यात किया जाएगा."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard आयात अनुरोध अस्वीकार हो गया था. बाद में पुन: प्रयास करें."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"संपर्क"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard को स्थानीय अस्थायी मेमोरी में संचित कर रहा है. वास्तविक आयात जल्दी ही प्रारंभ होगा."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard आयात नहीं कर सका."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC पर प्राप्त संपर्क"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"संपर्क निर्यात करें?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"संचय कर रहा है"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g> आयात कर रहा है: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"सेटिंग"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"दिखाई देने वाले संपर्क साझा करें"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"संपर्क आयात/निर्यात करें"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"संपर्क आयात करें"</string>
+ <string name="share_error" msgid="948429331673358107">"यह संपर्क साझा नहीं किया जा सकता."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"खोज"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"प्रदर्शन के लिए संपर्क"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"प्रदर्शन के लिए संपर्क"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"पसंदीदा"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"कोई संपर्क नहीं."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"अक्सर किए जाने वाले साफ़ करें"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"सिम कार्ड चुनें"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"आयात करें/निर्यात करें"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"अवरोधित नंबर"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g> द्वारा"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="SOURCE">%2$s</xliff:g> द्वारा <xliff:g id="DATE">%1$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"खोज साफ़ करें"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index ca0d695..f217372 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -239,9 +239,9 @@
<string name="set_default" msgid="4417505153468300351">"Postavi zadano"</string>
<string name="clear_default" msgid="7193185801596678067">"Izbriši zadano"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Tekst kopiran"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Želite li odbaciti promjene i prekinuti uređivanje?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Želite li odbaciti izmjene?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Odbaci"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Nastavi uređivati"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Odustani"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Pretraživanje kontakata"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Uklanjanje kontakata"</string>
@@ -266,7 +266,6 @@
<string name="about_card_title" msgid="2920942314212825637">"O kartici"</string>
<string name="send_message" msgid="8938418965550543196">"Pošalji poruku"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Stvaranje osobne kopije..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Jučer"</string>
<string name="tomorrow" msgid="6241969467795308581">"Sutra"</string>
<string name="today" msgid="8041090779381781781">"Danas"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Danas u <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -353,4 +352,335 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Poruke"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organiziranje popisa"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Brisanje duplikata i grupnih kontakata prema oznaci"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Tekst kopiran"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopiraj u međuspremnik"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Nazovi <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Nazovi kućni"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Nazovi mobitel"</string>
+ <string name="call_work" msgid="5328785911463744028">"Nazovi poslovni"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Nazovi poslovni faks"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Nazovi faks kod kuće"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Nazovi dojavljivač"</string>
+ <string name="call_other" msgid="8563753966926932052">"Pozovi"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Pozovi povratno"</string>
+ <string name="call_car" msgid="3280537320306436445">"Nazovi automobil"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Nazovi glavni u tvrtki"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Nazovi ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Pozovi glavni"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Pozovi faks"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Nazovi radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Nazovi teleks"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Nazovi TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Nazovi poslovni mobitel"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Nazovi poslovni dojavljivač"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Nazovi <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Nazovi MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Poruka za <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Poruka na kućni"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Poruka na mobitel"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Poruka na poslovni"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Poruka na poslovni faks"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Poruka na kućni faks"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Poruka na dojavljivač"</string>
+ <string name="sms_other" msgid="806127844607642331">"Tekst"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Poruka za povratni poziv"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Poruka u automobil"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Poruka na glavni u tvrtki"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Poruka na ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Poruka na glavni"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Poruka na faks"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Poruka na radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Poruka na teleks"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Poruka za TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Poruka na poslovni mobitel"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Poruka na poslovni dojavljivač"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Poruka za <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Poruka na MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Brisati podatke o čestim kontaktima?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Brisanje često kontaktiranih..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Dostupan"</string>
+ <string name="status_away" msgid="1838861100379804730">"Odsutan"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Zauzet"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontakti"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Drugo"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Direktorij"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Svi kontakti"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Pretraživanje..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Pronađeno je više od ovoliko kontakata: <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Nema kontakata"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> pronađeni</item>
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> pronađena</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> pronađenih</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Brzi kontakt za korisnika <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Bez imena)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Često kontaktirani"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Prikaži kontakt"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Svi kontakti s telefonskim brojevima"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Prikaži ažuriranja"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Ime"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Nadimak"</string>
+ <string name="full_name" msgid="6602579550613988977">"Ime"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Prefiks imena"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Srednje ime"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Sufiks imena"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Ime fonetski"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetsko srednje ime"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-pošta"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adresa"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizacija"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Odnos"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Tekstualna poruka"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adresa"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Tvrtka"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Naslov"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Bilješke"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Web-lokacija"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"E-poruka na privatnu e-poštu"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-pošta na mobitel"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-pošta na poslovni"</string>
+ <string name="email_other" msgid="3454004077967657109">"E-pošta"</string>
+ <string name="email_custom" msgid="7548003991586214105">"E-pošta <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-pošta"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Ulica"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Poštanski sandučić"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Susjedstvo"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Grad"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Država"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Poštanski broj"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Zemlja"</string>
+ <string name="map_home" msgid="1243547733423343982">"Prikaz kućne adrese"</string>
+ <string name="map_work" msgid="1360474076921878088">"Prikaži adresu na poslu"</string>
+ <string name="map_other" msgid="3817820803587012641">"Prikaz adrese"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Prikaz <xliff:g id="CUSTOM">%s</xliff:g> adresa"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Chatajte koristeći AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chatajte koristeći Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chatanje koristeći Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chatajte koristeći Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chatajte koristeći QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chatajte koristeći Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chatajte koristeći ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chatajte koristeći Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chat"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"izbriši"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Proširi ili sažmi nazive polja"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Svi kontakti"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Sa zvjezdicom"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Prilagodi"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontakt"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Svi ostali kontakti"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Svi kontakti"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Ukloni grupu sinkronizacije"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Dodaj grupu sinkroniziranja"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Više grupa..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Uklanjanje grupe \"<xliff:g id="GROUP">%s</xliff:g>\" iz sinkronizacije uklonit će i sve negrupirane kontakte iz sinkronizacije."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Spremanje opcija prikaza..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Gotovo"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Odustani"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Uvezi sa SIM kartice"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Otkazati uvoz datoteke <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Otkazati izvoz datoteke <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Uvoz/izvoz kartice vCard nije otkazan"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Nepoznata pogreška."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Datoteku \"<xliff:g id="FILE_NAME">%s</xliff:g>\" nije moguće otvoriti radi: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Alat za izvoz ne može se pokrenuti; razlog: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Nema kontakata koji se mogu izvoziti."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Tijekom izvoza došlo je do pogreške zbog: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Obavezan naziv datoteke predug je (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O pogreška"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Nema dovoljno memorije. Datoteka je možda prevelika."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Iz neočekivanog razloga nije moguće analizirati vCard datoteku."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Format nije podržan."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Neuspješno prikupljanje meta-informacija danih datoteka kartice vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Uvoz jedne ili više datoteka nije uspio (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Završetak izvoza datoteke <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Izvoz datoteke <xliff:g id="FILENAME">%s</xliff:g> otkazan je."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Izvoz podataka o kontaktu"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Dohvaćanje podataka iz baze podataka nije uspjelo."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Nema kontakata koji se mogu izvoziti. Ako na svojem telefonu imate kontakte, neki davatelji podataka možda ne dopuštaju izvoz kontakata s tog telefona."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Sastavljač za vCard nije se ispravno pokrenuo."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Izvoz nije uspio"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Podaci o kontaktu nisu izvezeni.\nRazlog: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Uvoz <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Čitanje podataka vCarda nije uspjelo"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Čitanje podataka vCard otkazano je"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Završetak uvoza kartice vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Uvoz datoteke <xliff:g id="FILENAME">%s</xliff:g> otkazan je"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Datoteka <xliff:g id="FILENAME">%s</xliff:g> uskoro će biti uvezena."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Datoteka će uskoro biti uvezena."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Zahtjev za uvoz formata vCard odbijen je. Pokušajte ponovo kasnije."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Datoteka <xliff:g id="FILENAME">%s</xliff:g> uskoro će biti izvezena."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Zahtjev za izvoz formata vCard odbijen je. Pokušajte ponovo kasnije."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontakt"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Spremanje vCard datoteka u predmemoriju za lokalnu privremenu pohranu. Stvarni uvoz uskoro će početi."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Uvoz vCard datoteke nije uspio."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontakt NFC-om"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Izvesti kontakte?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Spremanje u predmemoriju"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Uvoz <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Postavke"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Dijeli vidljive kontakte"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Uvoz/izvoz kontakata"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Uvezi kontakte"</string>
+ <string name="share_error" msgid="948429331673358107">"Ovaj kontakt nije moguće dijeliti."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Pretraži"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kontakti za prikaz"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kontakti za prikaz"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriti"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Nema kontakata."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Briši često kontaktirane"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Odaberi SIM karticu"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Uvoz/izvoz"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blokirani brojevi"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"preko izvora <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> preko izvora <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Brisanje pretraživanja"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 454e07f..5543b47 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -51,7 +51,7 @@
<string name="menu_create_contact_shortcut" msgid="1217971915748509640">"Kezdőképernyőre"</string>
<string name="menu_call" msgid="3992595586042260618">"Ismerős hívása"</string>
<string name="menu_sendSMS" msgid="5535886767547006515">"SMS küldése ismerősnek"</string>
- <string name="menu_splitAggregate" msgid="2627252205317945563">"Társítás megszüntetése"</string>
+ <string name="menu_splitAggregate" msgid="2627252205317945563">"Szétválasztás"</string>
<string name="menu_editGroup" msgid="6696843438454341063">"Névjegyek eltávolítása"</string>
<string name="menu_renameGroup" msgid="7169512355179757182">"Címke átnevezése"</string>
<string name="menu_deleteGroup" msgid="1126469629233412249">"Címke törlése"</string>
@@ -62,12 +62,12 @@
<string name="menu_new_contact_action_bar" msgid="7371001434034419566">"Névjegy hozzáadása"</string>
<string name="menu_new_group_action_bar" msgid="8726987769872493051">"Új létrehozása…"</string>
<string name="splitConfirmation" msgid="7342030840130187290">"Szeretné több névjegyre szétbontani ezt a névjegyet?"</string>
- <string name="splitConfirmation_positive_button" msgid="9129409098807939699">"Szétbontás"</string>
+ <string name="splitConfirmation_positive_button" msgid="9129409098807939699">"Szétválasztás"</string>
<string name="splitConfirmationWithPendingChanges" msgid="7719062163511895696">"Szeretné menteni a végrehajtott módosításokat, és több névjeggyé szétbontani ezt a névjegyet?"</string>
<string name="splitConfirmationWithPendingChanges_positive_button" msgid="9073444264887244032">"Mentés és szétbontás"</string>
<string name="joinConfirmation" msgid="8262614843581924365">"Szeretné menteni a végrehajtott módosításokat, és társítani a kiválasztott névjegyet?"</string>
<string name="joinConfirmation_positive_button" msgid="4573092849769149516">"Mentés és társítás"</string>
- <string name="menu_joinAggregate" msgid="3599512127797513606">"Társítás"</string>
+ <string name="menu_joinAggregate" msgid="3599512127797513606">"Összekapcsolás"</string>
<string name="menu_save" msgid="1727844363591825909">"Mentés"</string>
<string name="titleJoinContactDataWith" msgid="6825255752748313944">"Névjegyek társítása"</string>
<string name="blurbJoinContactDataWith" msgid="5864256698061641841">"Válassza ki a névjegyet, amelyet a következővel szeretne társítani: <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Beállítás alapértelmezettként"</string>
<string name="clear_default" msgid="7193185801596678067">"Alapértelmezés törlése"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Másolt szöveg"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Elveti a módosításokat, és kilép a szerkesztésből?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Elveti a módosításokat?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Elvetés"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Szerkesztés folytatása"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Mégse"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> -- <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Keresés a névjegyek között"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Névjegyek eltávolítása"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Névjegy"</string>
<string name="send_message" msgid="8938418965550543196">"Üzenet küldése"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Személyes másolat készítése..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Tegnap"</string>
<string name="tomorrow" msgid="6241969467795308581">"Holnap"</string>
<string name="today" msgid="8041090779381781781">"Ma"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Ma <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -298,7 +297,7 @@
<item quantity="other">Társított névjegyek (<xliff:g id="COUNT">%d</xliff:g>)</item>
<item quantity="one">Társított névjegy</item>
</plurals>
- <string name="quickcontact_contacts_number" msgid="6036916944287597682">"<xliff:g id="COUNT">%d</xliff:g> társított névjegy"</string>
+ <string name="quickcontact_contacts_number" msgid="6036916944287597682">"<xliff:g id="COUNT">%d</xliff:g> összekapcsolt névjegy"</string>
<string name="quick_contact_display_name_with_phonetic" msgid="3692038078718876610">"<xliff:g id="DISPLAY_NAME">%s</xliff:g> (<xliff:g id="PHONETIC_NAME">%s</xliff:g>)"</string>
<string name="quickcontact_suggestion_link_button" msgid="3244619714781727946">"NÉVJEGYEK TÁRSÍTÁSA"</string>
<string name="quickcontact_suggestion_cancel_button" msgid="8236954313106630862">"MÉGSE"</string>
@@ -318,7 +317,7 @@
<string name="suggestion_card_this_contact_title" msgid="3039457405374454914">"Ez a névjegy"</string>
<string name="suggestion_card_duplicates_title" msgid="9107788743178980902">"Lehetséges ismétlődések"</string>
<string name="suggestion_card_help_message" msgid="4474061044387181093">"Lehet, hogy ezek a névjegyek ugyanahhoz a személyhez tartoznak. Lehetőség van a névjegyek egyesítésére."</string>
- <string name="compact_editor_linked_contacts_title" msgid="4417919183651782674">"Társított névjegyek"</string>
+ <string name="compact_editor_linked_contacts_title" msgid="4417919183651782674">"Összekapcsolt névjegyek"</string>
<string name="from_your_accounts" msgid="1746293107836889912">"Az Ön fiókjaiból"</string>
<string name="take_a_photo_button" msgid="6268693854069113488">"Fotó készítése"</string>
<string name="all_photos_button" msgid="1943122929420111351">"Az összes fotó"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Üzenetek"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Rendszerezze a listát"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Törölje az ismétlődéseket, és csoportosítsa a névjegyeket címke szerint"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Másolt szöveg"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Másolás vágólapra"</string>
+ <string name="call_custom" msgid="7756571794763171802">"<xliff:g id="CUSTOM">%s</xliff:g> hívása"</string>
+ <string name="call_home" msgid="1990519474420545392">"Otthoni szám hívása"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Mobil hívása"</string>
+ <string name="call_work" msgid="5328785911463744028">"Munkahelyi telefon hívása"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Munkahelyi fax hívása"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Otthoni fax hívása"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Csipogó hívása"</string>
+ <string name="call_other" msgid="8563753966926932052">"Hívás"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Visszahívási szám hívása"</string>
+ <string name="call_car" msgid="3280537320306436445">"Gépkocsi hívása"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Céges fővonal hívása"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"ISDN-telefon hívása"</string>
+ <string name="call_main" msgid="6082900571803441339">"Fő telefonszám hívása"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Fax hívása"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Rádiótelefon hívása"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Telex hívása"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"TTY/TDD-szám hívása"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Munkahelyi mobil hívása"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Munkahelyi csipogó hívása"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"<xliff:g id="ASSISTANT">%s</xliff:g> hívása"</string>
+ <string name="call_mms" msgid="6274041545876221437">"MMS-ben szereplő telefonszám hívása"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"SMS küldése ide: <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"SMS küldése haza"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"SMS küldése mobiltelefonra"</string>
+ <string name="sms_work" msgid="2269624156655267740">"SMS küldése munkahelyi telefonra"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"SMS küldése munkahelyi faxszámra"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"SMS küldése otthoni faxszámra"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"SMS küldése csipogóra"</string>
+ <string name="sms_other" msgid="806127844607642331">"SMS küldése"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"SMS küldése visszahívandó számra"</string>
+ <string name="sms_car" msgid="7444227058437359641">"SMS küldése gépkocsinak"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"SMS küldése a céges fővonalra"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"SMS küldése ISDN-telefonra"</string>
+ <string name="sms_main" msgid="8621625784504541679">"SMS küldése fő telefonszámra"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"SMS küldése faxszámra"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"SMS küldése rádiótelefonra"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"SMS küldése telexre"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"SMS küldése szöveges telefonra (TTY/TDD)"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"SMS küldése munkahelyi mobilra"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"SMS küldése munkahelyi csipogóra"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"SMS küldése ide: <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"SMS küldése MMS-ben szereplő számra"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Törli a gyakran keresetteket?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Gyakran keresettek törlése..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Elérhető"</string>
+ <string name="status_away" msgid="1838861100379804730">"Nincs a gépnél"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Elfoglalt"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Címtár"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Egyéb"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Mappa"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Összes névjegy"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Keresés..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Több mint <xliff:g id="COUNT">%d</xliff:g> találat."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Nincsenek névjegyek"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> találat</item>
+ <item quantity="one">1 találat</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> gyors elérése"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Nincs név)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Gyakran keresett"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Névjegy megtekintése"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Minden névjegy telefonszámokkal"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Frissítések"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Név"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Becenév"</string>
+ <string name="full_name" msgid="6602579550613988977">"Név"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Név előtagja"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Második név"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Név utótagja"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Név fonetikusan"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Második utónév fonetikusan"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mail cím"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Cím"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Azonnali üzenetküldés"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Szervezet"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Kapcsolat"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Szöveges üzenet"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Cím"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Cég"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Beosztás"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Jegyzetek"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Webhely"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"E-mail küldése haza"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-mail küldése mobiltelefonra"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-mail küldése munkahelyi címre"</string>
+ <string name="email_other" msgid="3454004077967657109">"E-mail küldése"</string>
+ <string name="email_custom" msgid="7548003991586214105">"E-mail küldése a(z) <xliff:g id="CUSTOM">%s</xliff:g> címre"</string>
+ <string name="email" msgid="5668400997660065897">"E-mail küldése"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Utca"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Postafiók"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Környék"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Település"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Állapot"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Irányítószám"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Ország"</string>
+ <string name="map_home" msgid="1243547733423343982">"Otthoni cím megtekintése"</string>
+ <string name="map_work" msgid="1360474076921878088">"Munkahelyi cím megtekintése"</string>
+ <string name="map_other" msgid="3817820803587012641">"Cím megtekintése"</string>
+ <string name="map_custom" msgid="6184363799976265281">"<xliff:g id="CUSTOM">%s</xliff:g> cím megtekintése"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Csevegés AIM-on"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Csevegés a Windows Live-on"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Csevegés a Yahoon"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Csevegés Skype használatával"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Csevegés a QQ-n"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Csevegés a Google Csevegő használatával"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Csevegés az ICQ-n"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Csevegés Jabberen"</string>
+ <string name="chat" msgid="9025361898797412245">"Csevegés"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"törlés"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Névmezők kinyitása és összecsukása"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Összes névjegy"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Csillaggal megjelölt"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Személyre szabás"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kapcsolat"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Az összes többi névjegy"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Összes névjegy"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Szinkronizálási csoport eltávolítása"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Szinkronizálási csoport hozzáadása"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"További csoportok..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Ha leállítja a(z) \"<xliff:g id="GROUP">%s</xliff:g>\" csoport szinkronizálását, ugyanez történik a nem csoportosított névjegyekkel is."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Megjelenítési beállítások mentése..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Kész"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Mégse"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importálás a SIM-kártyáról"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Megszakítja <xliff:g id="FILENAME">%s</xliff:g> importálását?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Megszakítja <xliff:g id="FILENAME">%s</xliff:g> exportálását?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard imp./exp. megszakítása sikertelen"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Ismeretlen hiba."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"A(z) \"<xliff:g id="FILE_NAME">%s</xliff:g>\" fájl nem nyitható meg: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Nem sikerült elindítani az exportálót: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Nincs exportálható névjegy."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Hiba történt az exportálás során: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"A fájlnév túl hosszú (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O hiba"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Nincs elég memória. Lehet, hogy túl nagy a fájl."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Váratlan ok miatt nem sikerült a vCard szintaktikai elemzése."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"A formátum nem támogatott."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Nem sikerült begyűjteni a vCard-fájl(ok) metaadatait."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Egy vagy több fájl nem importálható (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"A(z) <xliff:g id="FILENAME">%s</xliff:g> exportálása befejeződött."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"A(z) <xliff:g id="FILENAME">%s</xliff:g> exportálása megszakítva."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Névjegyadatok exportálása"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Nem sikerült lekérni az adatbázis-információkat."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Nincsenek exportálható névjegyek. Ha vannak névjegyek a telefonján, akkor előfordulhat, hogy az adatszolgáltató nem teszi lehetővé a névjegyek exportálását a telefonról."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"A vCard-készítő nem megfelelően indult el."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Sikertelen export"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Nem sikerült a névjegyadatok exportálása.\nOk: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importálás - <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Nem sikerült beolvasni a vCard adatait."</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"A vCard-adatok beolvasása megszakítva"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"A(z) <xliff:g id="FILENAME">%s</xliff:g> vCard importálása befejeződött"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"A(z) <xliff:g id="FILENAME">%s</xliff:g> importálása megszakítva"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"A(z) <xliff:g id="FILENAME">%s</xliff:g> hamarosan importálásra kerül."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"A fájl importálása hamarosan megtörténik."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"A vCard-importálási kérelem elutasítva. Próbálja újra később."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"A(z) <xliff:g id="FILENAME">%s</xliff:g> hamarosan exportálásra kerül."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"A vCard-exportálási kérelem elutasítva. Próbálja újra később."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kapcsolat"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard(ok) mentése az ideiglenes helyi tárolóba. A tényleges importálás hamarosan megkezdődik."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Nem sikerült a vCard importálása."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC-n kapott névjegy"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exportálni szeretné?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Gyorsítótárazás"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importálás - <xliff:g id="TOTAL_NUMBER">%s</xliff:g>/<xliff:g id="CURRENT_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Beállítások"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Látható névjegyek megosztása"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Névjegyek importálása/exportálása"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Névjegyek importálása"</string>
+ <string name="share_error" msgid="948429331673358107">"Ez a névjegy nem osztható meg."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Keresés"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Megjelenítendő névjegyek"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Megjelenítendő névjegyek"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Kedvencek"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Nincsenek névjegyek"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Gyakran keresettek törlése"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM kártya kiválasztása"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importálás/exportálás"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Letiltott számok"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"- <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> - <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Keresés törlése"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index 2c80ad2..764dc04 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Սահմանել լռելյայն"</string>
<string name="clear_default" msgid="7193185801596678067">"Մաքրել լռելյայն"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Տեքսը պատճենված է"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Անտեսե՞լ փոփոխությունները և դադարեցնել խմբագրումը:"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Չեղարկե՞լ փոփոխությունները:"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Անտեսել"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Շարունակել խմբագրումը"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Չեղարկել"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Որոնեք կոնտակտներ"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Կոնտակտների հեռացում"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Տեղեկատվություն"</string>
<string name="send_message" msgid="8938418965550543196">"Ուղարկել հաղորդագրություն"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Ստեղծվում է անձնական պատճենը..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Երեկ"</string>
<string name="tomorrow" msgid="6241969467795308581">"Վաղը"</string>
<string name="today" msgid="8041090779381781781">"Այսօր"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Այսօր՝ <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Հաղորդագրություններ"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Կազմակերպեք ձեր ցանկը"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Մաքրեք կրկնօրինակները և խմբավորեք կոնտակտներն ըստ պիտակների"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Տեքսը պատճենված է"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Պատճենել սեղմատախտակին"</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="8563753966926932052">"Զանգել"</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="5745314124619636674">"Զանգել ֆաքսի համարին"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Հաղորդագրել"</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="3888842199855843152">"Հաղորդագրել ֆաքսի համարին"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Մաքրե՞լ հաճախակի հաղորդակցվողները"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Մաքրվում է հաճախակի հաղորդակցվողները..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Հասանելի է"</string>
+ <string name="status_away" msgid="1838861100379804730">"Տեղում չէ"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Զբաղված է"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Կոնտակտներ"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Այլ"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Գրացուցակ"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Բոլոր կոնտակտները"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Որոնում..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Գտնվել են ավելի քան <xliff:g id="COUNT">%d</xliff:g>:"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Կոտնակտներ չկան"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one">Գտնվել է <xliff:g id="COUNT">%d</xliff:g> կոնտակտ</item>
+ <item quantity="other">Գտնվել է <xliff:g id="COUNT">%d</xliff:g> կոնտակտ</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Արագ հաղորդակցում <xliff:g id="NAME">%1$s</xliff:g>-ի հետ"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Անանուն)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Հաճախակի հաղորդակցվածները"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Դիտել կոնտակտը"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Բոլոր հեռախոսահամարներով կոնտակտները"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Դիտել թարմացումները"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Անունը"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Մականունը"</string>
+ <string name="full_name" msgid="6602579550613988977">"Անունը"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Հնչյունաբանական անունը"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Հնչյունաբանական հայրանունը"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Հեռախոսը"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Էլփոստ"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Հասցե"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Կազմակերպություն"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Հարաբերություններ"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Տեքստային հաղորդագրություն"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Հասցեն"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Ընկերությունը"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Վերնագիրը"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Գրառումներ"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Վեբ-կայք"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"Նամակագրել"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Նամակագրել <xliff:g id="CUSTOM">%s</xliff:g>-ին"</string>
+ <string name="email" msgid="5668400997660065897">"Նամակագրել"</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="map_home" msgid="1243547733423343982">"Դիտել բնակության հասցեն"</string>
+ <string name="map_work" msgid="1360474076921878088">"Դիտել աշխատավայրի հասցեն"</string>
+ <string name="map_other" msgid="3817820803587012641">"Դիտել հասցեն"</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="description_minus_button" msgid="6908099247930477551">"ջնջել"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Ընդարձակել կամ սեղմել անվան դաշտերը"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Բոլոր կոնտակտները"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Աստղանշված"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Հարմարեցնել"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Կոնտակտ"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Բոլոր այլ կոնտակտները"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Բոլոր կոնտակտները"</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_warn_remove_ungrouped" msgid="8872290721676651414">"«<xliff:g id="GROUP">%s</xliff:g>»-ի հեռացումը համաժամեցումից նաև կհեռացնի ցանկացած չխմբավորված կոնտակտ համաժամեցումից:"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Ցուցադրման ընտրանքները պահվում են..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Կատարված է"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Չեղարկել"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Ներմուծել SIM քարտից"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Չեղարկե՞լ <xliff:g id="FILENAME">%s</xliff:g>-ի ներմուծումը"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Չեղարկե՞լ <xliff:g id="FILENAME">%s</xliff:g>-ի արտահանումը"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Հնարավոր չէ չեղարկել vCard-ի ներմուծումը/արտահանումը"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Անհայտ սխալ:"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Հնարավոր չէ բացել \"<xliff:g id="FILE_NAME">%s</xliff:g>\"-ը. պատճառը` <xliff:g id="EXACT_REASON">%s</xliff:g>:"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Հնարավոր չէ մեկնարկել արտահանողը. պատճառը` «<xliff:g id="EXACT_REASON">%s</xliff:g>»:"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Արտահանելի կոնտակտ չկա:"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Արտահանման ընթացքում տեղի է ունեցել սխալ. պատճառը` «<xliff:g id="EXACT_REASON">%s</xliff:g>»:"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Պահանջվող ֆայլի անունը շատ երկար է («<xliff:g id="FILENAME">%s</xliff:g>»):"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O սխալ"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Հիշողությունը բավարար չէ: Հնարավոր է` ֆայլը չափազանց մեծ է:"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Չնախատեսված պատճառով vCard-ը հնարավոր չէ վերծանել:"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Ձևաչափը չի աջակցվում:"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Հնարավոր չէ հավաքագրել տվյալ vCard ֆայլի(երի) մետա տեղեկատվությունը:"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Հնարավոր չէ ներմուծել մեկ կամ ավելի ֆայլեր (%s):"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g>-ի արտահանումը ավարտվեց"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g>-ի արտահանումը չեղարկվեց:"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Կոնտակտային տվյալների արտահանում"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Հնարավոր չէ ստանալ տվյալների շտեմարանի տեղեկատվությունը:"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Արտահանելի կոնտակտներ չկան: Եթե դուք իրականում ունեք կոնտակտներ ձեր հեռախոսում, ապա հնարավոր է` որոշ տվյալների մատակարարներ չեն թույլատրում կոնտակտների արտահանումը հեռախոսից:"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard-ի կազմիչը ճիշտ չէ մեկնարկել:"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Հնարավոր չէ արտահանել"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Կոնտակտային տվյալները չեն արտահանվել:\nՊատճառը՝ «<xliff:g id="FAIL_REASON">%s</xliff:g>»"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g>-ը ներմուծվում է"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Հնարավոր չէ ընթերցել vCard-ի տվյալները"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard-ի տվյալների ընթերցումը չեղարկվեց"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"<xliff:g id="FILENAME">%s</xliff:g>-ի ներմուծումը vCard ավարտվեց"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g>-ի ներմուծումը չեղարկվեց"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g>-ը կներմուծվի շուտով:"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Ֆայլը կներմուծվի շուտով:"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard-ի ներմուծման հայցը մերժվեց: Փորձեք կրկին ավելի ուշ:"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g>-ը կարտահանվի շուտով:"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard-ի արտահանման հայցը մերժվել է: Կրկին փորեք ավելի ուշ:"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"կոնտակտ"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard(եր)-ի քեշավորում տեղային ժամանակավոր պահոց: Ներմուծումը կսկսվի շուտով:"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Հնարավոր չէ ներմուծել vCard-ը:"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC-ով ստացված կոտակտ"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Արտահանե՞լ կոնտկատները"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Քեշավորում"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g> / <xliff:g id="TOTAL_NUMBER">%s</xliff:g> : <xliff:g id="NAME">%s</xliff:g>-ի ներմուծում"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Կարգավորումներ"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Տարածել տեսանելի կոնտակտները"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Ներմուծել/արտահանել կոնտակտներ"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Ներմուծել կոնտակտներ"</string>
+ <string name="share_error" msgid="948429331673358107">"Չհաջողվեց կիսվել կոնտակտով:"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Որոնել"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Ցուցադրվող կոնտակտները"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Ցուցադրման կոնտակտները"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Ընտրյալներ"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Կոնտակտներ չկան:"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Մաքրել ամենաշատ զանգվածները"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Ընտրեք SIM քարտը"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Ներմուծել/արտահանել"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Արգելափակված համարներ"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g>-ի միջոցով"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="SOURCE">%2$s</xliff:g>-ով"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Մաքրել որոնման դաշտը"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 598d168..ea65a0e 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Setel sebagai default"</string>
<string name="clear_default" msgid="7193185801596678067">"Hapus default"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Teks disalin"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Buang perubahan dan berhenti mengedit?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Buang perubahan?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Buang"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Simpan pengeditan"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Batal"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Telusuri kontak"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Hapus kontak"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Tentang"</string>
<string name="send_message" msgid="8938418965550543196">"Kirim pesan"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Membuat salinan pribadi..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Kemarin"</string>
<string name="tomorrow" msgid="6241969467795308581">"Besok"</string>
<string name="today" msgid="8041090779381781781">"Hari ini"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Hari ini pukul <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Pesan"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Atur daftar kontak Anda"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Membersihkan kontak duplikat & grup berdasarkan label"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Teks disalin"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Salin ke papan klip"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Telepon <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Telepon nomor telepon rumah"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Telepon nomor seluler"</string>
+ <string name="call_work" msgid="5328785911463744028">"Telepon nomor kantor"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Telepon faks kantor"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Telepon nomor faks rumah"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Telepon pager"</string>
+ <string name="call_other" msgid="8563753966926932052">"Telepon"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Hubungi panggilan balik"</string>
+ <string name="call_car" msgid="3280537320306436445">"Hubungi nomor telepon mobil"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Hubungi nomor telepon utama perusahaan"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Telepon ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Telepon nomor utama"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Telepon faks"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Telepon radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Telepon teleks"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Telepon TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Telepon nomor seluler kantor"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Telepon pager kantor"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Telepon <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Telepon MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"SMS <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"SMS rumah"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"SMS seluler"</string>
+ <string name="sms_work" msgid="2269624156655267740">"SMS kantor"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"SMS faks kantor"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"SMS faks rumah"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"SMS pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"SMS"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"SMS panggilan balik"</string>
+ <string name="sms_car" msgid="7444227058437359641">"SMS mobil"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"SMS nomor utama perusahaan"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"SMS ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"SMS utama"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"SMS faks"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"SMS 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 seluler kantor"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Teks pager kantor"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"SMS <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"SMS MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Hapus yang sering dihubungi?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Menghapus yang sering dihubungi..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Ada"</string>
+ <string name="status_away" msgid="1838861100379804730">"Tidak di Tempat"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Sibuk"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontak"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Lainnya"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Direktori"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Semua kontak"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Menelusuri..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Ditemukan lebih dari <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Tidak ada kontak"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ditemukan</item>
+ <item quantity="one">1 ditemukan</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Kontak cepat untuk <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Tanpa nama)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Paling sering dihubungi"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Lihat kontak"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Semua kontak dengan nomor telepon"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Lihat pembaruan"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nama"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Nama panggilan"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nama"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Awalan nama"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Nama tengah"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Akhiran nama"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nama fonetik"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Nama tengah fonetik"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telepon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Email"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Alamat"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisasi"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Hubungan"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Pesan teks"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Alamat"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Perusahaan"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Judul"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Catatan"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Situs web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Email ke rumah"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Email ke seluler"</string>
+ <string name="email_work" msgid="2807430017302722689">"Email ke kantor"</string>
+ <string name="email_other" msgid="3454004077967657109">"Email"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Email <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Email"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Jalan"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Kotak pos"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Lingkungan"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Kota"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Neg. Bagian/Prov"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Kode pos"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Negara"</string>
+ <string name="map_home" msgid="1243547733423343982">"Tampilkan alamat rumah"</string>
+ <string name="map_work" msgid="1360474076921878088">"Tampilkan alamat kantor"</string>
+ <string name="map_other" msgid="3817820803587012641">"Lihat alamat"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Tampilkan alamat <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Ngobrol menggunakan AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Ngobrol menggunakan Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Ngobrol menggunakan Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Ngobrol menggunakan Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Ngobrol menggunakan QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Ngobrol menggunakan Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Ngobrol menggunakan ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Ngobrol menggunakan Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Ngobrol"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"hapus"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Luaskan atau ciutkan bidang nama"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Semua kontak"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Yang berbintang"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Khusus"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontak"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Semua kontak lainnya"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Semua kontak"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Hapus grup sinkronisasi"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Tambahkan grup sinkronisasi"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Grup lainnya..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Menghapus \"<xliff:g id="GROUP">%s</xliff:g>\" dari sinkronisasi juga akan menghapus setiap kontak yang tidak berada dalam grup dari sinkronisasi."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Menyimpan opsi tampilan..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Selesai"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Batal"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Impor dari kartu SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Batalkan impor <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Batalkan ekspor <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Tidak dpt membatalkan impor/ekspor vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Kesalahan tidak dikenal."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Tidak dapat membuka \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Tidak dapat memulai pengeskpor: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Tidak ada kontak yang dapat diekspor."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Terjadi kesalahan saat ekspor: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Nama file yang diperlukan terlalu panjang (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Kesalahan I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Memori tidak cukup. File mungkin terlalu besar."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Tidak dapat mengurai vCard karena alasan yang tak terduga."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Format tidak didukung."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Tidak dapat mengumpulkan informasi meta dari file vCard yang diberikan."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Satu file atau lebih tidak dapat diimpor (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Selesai mengekspor <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Mengekspor <xliff:g id="FILENAME">%s</xliff:g> dibatalkan."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Mengekspor kontak"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Tidak dapat memperoleh informasi basis data."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Tidak ada kontak yang dapat diekspor. Jika Anda menyimpan kontak pada ponsel, beberapa penyedia data tidak mengizinkan kontak diekspor dari ponsel."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Penyusun vCard tidak memulai dengan semestinya."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Tak dapat mengekspor"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Kontak tidak diekspor.\nAlasan: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Mengimpor <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Tidak dapat membaca data vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Membaca data vCard dibatalkan"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Selesai mengimpor vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Mengimpor <xliff:g id="FILENAME">%s</xliff:g> dibatalkan"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> akan segera diimpor."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"File akan diimpor segera."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Permintaan impor vCard ditolak. Coba lagi nanti."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> akan segera diekspor."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Permintaan ekspor vCard ditolak. Coba lagi nanti."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontak"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Menyimpan vCard ke cache untuk penyimpanan lokal sementara. Impor yang sebenarnya akan segera dimulai."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Tidak dapat mengimpor vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontak yang diterima lewat NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Ekspor kontak?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Menyimpan ke cache"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Mengimpor <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Setelan"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Bagikan kontak yang terlihat"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Impor/ekspor kontak"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Impor kontak"</string>
+ <string name="share_error" msgid="948429331673358107">"Kontak ini tidak dapat dibagi."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Telusuri"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kontak untuk ditampilkan"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kontak untuk ditampilkan"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favorit"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Tidak ada kontak."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Hapus yang sering"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Pilih kartu SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Impor/ekspor"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Nomor yang diblokir"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"melalui <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> melalui <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Hapus penelusuran"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
index 0bae040..33b7e5d 100644
--- a/res/values-is-rIS/strings.xml
+++ b/res/values-is-rIS/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Velja sem sjálfgefið"</string>
<string name="clear_default" msgid="7193185801596678067">"Hreinsa sjálfgefið"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Texti afritaður"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Viltu fleygja breytingum og hætta að breyta?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Fleygja breytingum?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Fleygja"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Breyta áfram"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Hætta við"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Leita í tengiliðum"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Fjarlægja tengiliði"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Um"</string>
<string name="send_message" msgid="8938418965550543196">"Senda skilaboð"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Býr til afrit til einkanota…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Í gær"</string>
<string name="tomorrow" msgid="6241969467795308581">"Á morgun"</string>
<string name="today" msgid="8041090779381781781">"Í dag"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Í dag klukkan <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Skilaboð"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Skipuleggðu listann þinn"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Hreinsaðu út tvítekningar og flokkaðu tengiliði"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Texti afritaður"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Afrita á klippiborð"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Hringja í <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Hringja heim"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Hringa í farsíma"</string>
+ <string name="call_work" msgid="5328785911463744028">"Hringja í vinnusíma"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Hringja í faxnúmer vinnu"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Hringja í faxnúmer heima"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Hringja í símboða"</string>
+ <string name="call_other" msgid="8563753966926932052">"Hringja"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Hringja svarhringingu"</string>
+ <string name="call_car" msgid="3280537320306436445">"Hringja í bílasíma"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Hringja í aðalsíma fyrirtækis"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Hringja í ISDN-númer"</string>
+ <string name="call_main" msgid="6082900571803441339">"Hringja í aðalnúmer"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Hringja í faxnúmer"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Hringja í talstöð"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Hringja í telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Hringja í fjarrita"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Hringja í vinnufarsíma"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Hringja í vinnusímboða"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Hringja í <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Hringja í MMS-númer"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Senda SMS-skilaboð til <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Senda SMS-skilaboð heim"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Senda SMS-skilaboð í farsíma"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Senda SMS-skilaboð í vinnusíma"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Senda SMS-skilaboð í faxnúmer vinnu"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Senda SMS-skilaboð í faxnúmer heima"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Senda SMS-skilaboð í símboða"</string>
+ <string name="sms_other" msgid="806127844607642331">"Senda SMS-skilaboð"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Senda SMS-skilaboð í svarhringingarnúmer"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Senda SMS-skilaboð í bílasíma"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Senda SMS-skilaboð í aðalnúmer fyrirtækis"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Senda SMS-skilaboð í ISDN-númer"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Senda SMS-skilaboð í aðalnúmer"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Senda SMS-skilaboð í faxnúmer"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Senda SMS-skilaboð í talstöð"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Senda SMS-skilaboð í telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Senda SMS-skilaboð til fjarrita"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Senda SMS-skilaboð í vinnufarsíma"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Senda SMS-skilaboð í vinnusímboða"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Senda SMS-skilaboð til <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Senda SMS-skilaboð í MMS-númer"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Hreinsa mest notuðu tengiliði?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Hreinsar mest notuðu tengiliði…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Laus"</string>
+ <string name="status_away" msgid="1838861100379804730">"Í burtu"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Upptekin(n)"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Tengiliðir"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Annað"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Skrá"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Allir tengiliðir"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Leitar…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Yfir <xliff:g id="COUNT">%d</xliff:g> fundust."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Engir tengiliðir"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> fannst</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> fundust</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Flýtitengiliður fyrir <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Nafn vantar)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Oft haft samband við"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Skoða tengilið"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Allir tengiliðir með símanúmer"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Skoða uppfærslur"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nafn"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Gælunafn"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nafn"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Forskeyti nafns"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Millinafn"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Viðskeyti nafns"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Hljóðrétt nafn"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Hljóðrétt millinafn"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Sími"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Netfang"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Heimilisfang"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Spjall"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Fyrirtæki"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Tengsl"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Senda SMS-skilaboð"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Heimilisfang"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Fyrirtæki"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titill"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Glósur"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Vefsvæði"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Senda tölvupóst heim"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Senda tölvupóst í fartæki"</string>
+ <string name="email_work" msgid="2807430017302722689">"Senda tölvupóst í vinnu"</string>
+ <string name="email_other" msgid="3454004077967657109">"Senda tölvupóst"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Senda tölvupóst til <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Netfang"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Gata"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Pósthólf"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Hverfi"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Borg"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Ríki"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Póstnúmer"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Land"</string>
+ <string name="map_home" msgid="1243547733423343982">"Skoða heimilisfang"</string>
+ <string name="map_work" msgid="1360474076921878088">"Skoða póstfang vinnu"</string>
+ <string name="map_other" msgid="3817820803587012641">"Skoða póstfang"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Skoða heimilisfang <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Spjalla með AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Spjalla með Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Spjalla með Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Spjalla með Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Spjalla með QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Spjalla með Google spjalli"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Spjalla með ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Spjalla með Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Spjalla"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"eyða"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Birta fleiri eða færri nafnareiti"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Allir tengiliðir"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Stjörnumerktir"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Sérsníða"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Tengiliður"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Allir aðrir tengiliðir"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Allir tengiliðir"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Fjarlægja samstillingarhóp"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Bæta við samstillingarhóp"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Fleiri hópar…"</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Ef hópurinn „<xliff:g id="GROUP">%s</xliff:g>“ er fjarlægður úr samstillingu verður samstillingu einnig hætt á öllum tengiliðum sem ekki eru í hóp."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Vistar birtingarvalkosti…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Lokið"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Hætta við"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Flytja inn af SIM-korti"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Hætta við innflutning á <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Hætta við útflutning á <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Ekki tókst að hætta við flutning vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Óþekkt villa."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Ekki tókst að opna „<xliff:g id="FILE_NAME">%s</xliff:g>“: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Ekki tókst að ræsa útflutningsverkfærið: „<xliff:g id="EXACT_REASON">%s</xliff:g>“."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Engir tengiliðir sem flytja má út."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Villa kom upp við útflutninginn: „<xliff:g id="EXACT_REASON">%s</xliff:g>“."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Skráarheitið er of langt („<xliff:g id="FILENAME">%s</xliff:g>“)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Inntaks-/úttaksvilla"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Ekki nægt minni. Skráin kann að vera of stór."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Ekki tókst að þátta vCard-skrána, af óþekktri ástæðu."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Ekki er stuðningur við sniðið."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Ekki tókst að safna lýsigögnum fyrir uppgefna(r) vCard-skrá(r)."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Ekki tókst að flytja inn eina eða fleiri skrár (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Útflutningi á <xliff:g id="FILENAME">%s</xliff:g> lokið."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Hætt við útflutning á <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Flytur út tengiliðagögn"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Ekki tókst að sækja upplýsingar úr gagnagrunni."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Engir tengiliðir til útflutnings. Ef þú ert með tengiliði í símanum getur verið að vissar gagnaveitur leyfi ekki útflutning tengiliða úr símanum."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Ræsing vCard-skrifviðmótsins tókst ekki."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Útflutningur mistókst"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Tengiliðagögn voru ekki flutt út.\nÁstæða: „<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Flytur inn <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Ekki tókst að lesa gögn úr vCard-skrá"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Hætt við lestur vCard-gagna"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Innflutningi lokið á vCard-skránni <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Hætt við innflutning á <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> verður flutt inn innan skamms."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Skráin verður flutt inn innan skamms."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Beiðni um innflutning vCard-skrár hafnað. Reyndu aftur síðar."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> verður flutt út innan skamms."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Beiðni um útflutning vCard-skrár hafnað. Reyndu aftur síðar."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"tengiliður"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Setur vCard í skyndiminni í staðbundinni geymslu. Raunverulegur innflutningur hefst innan skamms."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Ekki tókst að flytja vCard-skrá inn."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Tengiliður móttekinn um NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Flytja út tengiliði?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Setur í skyndiminni"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Flytur inn <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Stillingar"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Deila sýnilegum tengiliðum"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Tengiliðir fluttir inn/út"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Flytja inn tengiliði"</string>
+ <string name="share_error" msgid="948429331673358107">"Ekki er hægt að deila þessum tengilið."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Leita"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Tengiliðir til að birta"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Tengiliðir til að birta"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Uppáhald"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Engir tengiliðir."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Hreinsa algenga tengiliði"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Veldu SIM-kort"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Flytja inn/út"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Númer á bannlista"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"í gegnum <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> í gegnum <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Hreinsa leit"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 78ea37b..64ce512 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Imposta come predefinito"</string>
<string name="clear_default" msgid="7193185801596678067">"Cancella impostazione predefinita"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Testo copiato"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Annullare le modifiche e uscire dalla modalità di modifica?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Ignorare le modifiche?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Ignora"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Continua la modifica"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Annulla"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Cerca contatti"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Rimuovi contatti"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Informazioni"</string>
<string name="send_message" msgid="8938418965550543196">"Invia messaggio"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Creazione di una copia personale..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Ieri"</string>
<string name="tomorrow" msgid="6241969467795308581">"Domani"</string>
<string name="today" msgid="8041090779381781781">"Oggi"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Oggi alle ore <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Messaggi"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organizza il tuo elenco"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Elimina i duplicati e raggruppa i contatti in base a etichette"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Testo copiato"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copia negli appunti"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Chiama n. <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Chiama casa"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Chiama cellulare"</string>
+ <string name="call_work" msgid="5328785911463744028">"Chiama n. lavoro"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Chiama fax lavoro"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Chiama n. fax casa"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Chiama cercapersone"</string>
+ <string name="call_other" msgid="8563753966926932052">"Chiama"</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="5745314124619636674">"Chiama n. fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Chiama radiotelefono"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Chiama telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Chiama n. TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Chiama cellulare lavoro"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Chiama cercapersone lavoro"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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 cellulare"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Invia SMS a n. lavoro"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Invia SMS a fax lavoro"</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="806127844607642331">"Invia SMS a n."</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="3888842199855843152">"Invia SMS a n. fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Invia SMS a radiotelefono"</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 cellulare lavoro"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"SMS a cercapersone lavoro"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Cancellare contattati di frequente?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Cancellazione contattati di frequente…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Disponibile"</string>
+ <string name="status_away" msgid="1838861100379804730">"Assente"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Occupato"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contatti"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Altro"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Directory"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Tutti i contatti"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Ricerca..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Ne sono stati trovati più di <xliff:g id="COUNT">%d</xliff:g>"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Nessun contatto"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> trovati</item>
+ <item quantity="one">1 trovato</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Contatto rapido per <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Nessun nome)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Contattati spesso"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Visualizza contatto"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Tutti i contatti con numeri di telefono"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Visualizza aggiornamenti"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nome"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Nickname"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nome"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Nome fonetico"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Secondo nome fonetico"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefono"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Email"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Indirizzo"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Chat"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizzazione"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relazione"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Messaggio di testo"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Indirizzo"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Società"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titolo"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Note"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Sito web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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. lavoro"</string>
+ <string name="email_other" msgid="3454004077967657109">"Invia email"</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="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="map_home" msgid="1243547733423343982">"Visualizza indirizzo casa"</string>
+ <string name="map_work" msgid="1360474076921878088">"Visualizza indirizzo lavoro"</string>
+ <string name="map_other" msgid="3817820803587012641">"Visualizza 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 su AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Chatta su Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Chatta su Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Chatta su Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Chatta su QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Chatta su Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Chatta su ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Chatta su Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Chatta"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"elimina"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Espandi o comprimi i campi dei nomi"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Tutti i contatti"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Speciali"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personalizza"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contatto"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Tutti gli altri contatti"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Tutti i contatti"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Se rimuovi \"<xliff:g id="GROUP">%s</xliff:g>\" dalla sincronizzazione, verranno rimossi anche gli eventuali contatti separati."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Salvataggio opzioni di visualizzazione..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Salva"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Annulla"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importa da scheda SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Annullare l\'importazione di <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Annullare l\'esportazione di <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Annullam. import./esport. vCard non riuscito"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Errore sconosciuto."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Apertura di \"<xliff:g id="FILE_NAME">%s</xliff:g>\" non riuscita: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Avvio dell\'utilità di esportazione non riuscito: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Nessun contatto esportabile."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Si è verificato un errore durante l\'esportazione: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Il nome file richiesto è troppo lungo (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Errore I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Memoria insufficiente. Il file potrebbe essere troppo grande."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Analisi vCard non riuscita per motivo imprevisto."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Il formato non è supportato."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Raccolta dei metadati dei file vCard specificati non riuscita."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Importazione di uno o più file non riuscita (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Esportazione di <xliff:g id="FILENAME">%s</xliff:g> terminata."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Esportazione di <xliff:g id="FILENAME">%s</xliff:g> annullata."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Esportazione dati di contatto"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Recupero informazioni database non riuscito."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Non sono presenti contatti esportabili. Se hai contatti sul telefono, è possibile che alcuni fornitori di dati non consentano l\'esportazione dei contatti dal telefono."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Il compositore di vCard non si è avviato correttamente."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Impossibile esportare"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"I dati dei contatti non sono stati esportati.\nMotivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importazione di <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Lettura dati vCard non riuscita"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Lettura dati vCard annullata"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Importazione vCard <xliff:g id="FILENAME">%s</xliff:g> terminata"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importazione di <xliff:g id="FILENAME">%s</xliff:g> annullata"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"La vCard <xliff:g id="FILENAME">%s</xliff:g> verrà importata a breve."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Il file sarà importato a breve."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Richiesta importazione vCard rifiutata. Riprova più tardi."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"La vCard <xliff:g id="FILENAME">%s</xliff:g> verrà esportata a breve."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Richiesta esportazione vCard rifiutata. Riprova più tardi."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contatto"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Memorizzazione delle vCard nella cache di archiviazione temporanea locale. L\'importazione reale inizierà a breve."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Importazione vCard non riuscita."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contatto ricevuto via NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Esportare contatti?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Memorizzazione nella cache"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importazione di <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Impostazioni"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Condividi contatti visibili"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importa/esporta contatti"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importa contatti"</string>
+ <string name="share_error" msgid="948429331673358107">"Questo contatto non può essere condiviso."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Cerca"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contatti da visualizzare"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contatti da visualizzare"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Preferiti"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Nessun contatto."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Cancella frequenti"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Seleziona scheda SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importa/esporta"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Numeri bloccati"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"tramite <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> tramite <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Cancella ricerca"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index ab62ba9..2007d9b 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -246,9 +246,9 @@
<string name="set_default" msgid="4417505153468300351">"קבע כברירת מחדל"</string>
<string name="clear_default" msgid="7193185801596678067">"נקה ברירת מחדל"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"טקסט שהועתק"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"האם להתעלם מהשינויים שביצעת ולהפסיק לערוך?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"האם לבטל את השינויים?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"מחק"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"המשך לערוך"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"ביטול"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"חיפוש אנשי קשר"</string>
<string name="title_edit_group" msgid="8602752287270586734">"הסרה של אנשי הקשר"</string>
@@ -273,7 +273,6 @@
<string name="about_card_title" msgid="2920942314212825637">"מידע כללי"</string>
<string name="send_message" msgid="8938418965550543196">"שלח הודעה"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"יוצר עותק אישי..."</string>
- <string name="yesterday" msgid="6840858548955018569">"אתמול"</string>
<string name="tomorrow" msgid="6241969467795308581">"מחר"</string>
<string name="today" msgid="8041090779381781781">"היום"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"היום ב-<xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -364,4 +363,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"הודעות"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"סידור הרשימה"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"מחק עותקים כפולים וקבץ את אנשי הקשר לפי תוויות"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"טקסט שהועתק"</string>
+ <string name="copy_text" msgid="3257145021583508761">"העתק ללוח"</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="8563753966926932052">"חייג"</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="5745314124619636674">"התקשר לפקס"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"הודעת טקסט"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"שלח הודעת טקסט למספר להתקשרות חזרה"</string>
+ <string name="sms_car" msgid="7444227058437359641">"שלח SMS לטלפון במכונית"</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="3888842199855843152">"שלח הודעת טקסט לפקס"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"האם למחוק אנשי קשר קבועים?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"מוחק אנשי קשר קבועים…"</string>
+ <string name="status_available" msgid="5586870015822828392">"זמין"</string>
+ <string name="status_away" msgid="1838861100379804730">"לא נמצא"</string>
+ <string name="status_busy" msgid="9147992455450257136">"עסוק"</string>
+ <string name="contactsList" msgid="8661624236494819731">"אנשי קשר"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"אחר"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"ספריה"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"כל אנשי הקשר"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"מחפש..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"נמצאו יותר מ-<xliff:g id="COUNT">%d</xliff:g> פריטים."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"אין אנשי קשר"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="two">נמצאו <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="many">נמצאו <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="other">נמצאו <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="one">אחד נמצא</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"קשר מהיר עבור <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(ללא שם)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"בקשר לעתים קרובות"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"הצג איש קשר"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"כל אנשי הקשר עם מספרי טלפון"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"הצג עדכונים"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"שם"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"כינוי"</string>
+ <string name="full_name" msgid="6602579550613988977">"שם"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"שם פונטי"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"שם אמצעי פונטי"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"טלפון"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"אימייל"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"כתובת"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"הודעה מיידית"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"ארגון"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"קשר"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"הודעת טקסט"</string>
+ <string name="postal_address" msgid="8765560217149624536">"כתובת"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"חברה"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"שם"</string>
+ <string name="label_notes" msgid="8337354953278341042">"הערות"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"אתר"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"אימייל"</string>
+ <string name="email_custom" msgid="7548003991586214105">"שלח אימייל אל <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"אימייל"</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="map_home" msgid="1243547733423343982">"הצג כתובת בית"</string>
+ <string name="map_work" msgid="1360474076921878088">"הצג כתובת עבודה"</string>
+ <string name="map_other" msgid="3817820803587012641">"הצג כתובת"</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="description_minus_button" msgid="6908099247930477551">"מחק"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"הרחב או כווץ שמות של שדות"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"כל אנשי הקשר"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"מסומן בכוכב"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"התאם אישית"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"איש קשר"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"כל אנשי הקשר האחרים"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"כל אנשי הקשר"</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_warn_remove_ungrouped" msgid="8872290721676651414">"הסרת \"<xliff:g id="GROUP">%s</xliff:g>\" מהסנכרון תסיר מהסנכרון גם אנשי קשר שאינם מקובצים."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"שומר אפשרויות תצוגה..."</string>
+ <string name="menu_done" msgid="796017761764190697">"סיום"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"בטל"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"ייבא מכרטיס SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"לבטל את הייבוא של <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"לבטל את הייצוא של <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"לא ניתן לבטל ייבוא/ייצוא של vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"שגיאה לא ידועה."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"לא ניתן לפתוח את \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"לא ניתן להפעיל את המייצא: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"אין אנשי קשר הניתנים לייצוא."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"אירעה שגיאה במהלך הייצוא: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"שם הקובץ הדרוש ארוך מדי (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"שגיאת קלט/פלט"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"אין מספיק זיכרון. ייתכן שהקובץ גדול מדי."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"אין אפשרות לנתח את ה-vCard מסיבה בלתי צפויה."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"הפורמט אינו נתמך."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"לא ניתן לאסוף מטא-מידע של קבצים נתונים של vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"לא ניתן לייבא קובץ אחד או יותר (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"הייצוא של <xliff:g id="FILENAME">%s</xliff:g> הסתיים."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"הייצוא של <xliff:g id="FILENAME">%s</xliff:g> בוטל."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"מייצא נתונים של אנשי קשר"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"לא ניתן לקבל מידע ממסד הנתונים."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"אין אנשי קשר הניתנים לייצוא. אם מוגדרים אנשי קשר בטלפון שלך, ייתכן שספקי נתונים מסוימים אינם מאפשרים ייצוא של אנשי קשר מהטלפון."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"יישום היצירה של ה-vCard לא הופעל כהלכה."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"לא ניתן לייצא"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"נתוני אנשי הקשר לא יוצאו.\nסיבה: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"מייבא את <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"לא ניתן לקרוא נתוני vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"קריאת נתוני ה-VCard בוטלה"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"הייבוא של vCard בשם <xliff:g id="FILENAME">%s</xliff:g> הסתיים"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"הייבוא של <xliff:g id="FILENAME">%s</xliff:g> בוטל"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"הייבוא של <xliff:g id="FILENAME">%s</xliff:g> יתבצע תוך זמן קצר."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"הייבוא של הקובץ יתבצע תוך זמן קצר."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"הבקשה לייבוא ה-vCard נדחתה. נסה שוב מאוחר יותר."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"הייצוא של <xliff:g id="FILENAME">%s</xliff:g> יתבצע תוך זמן קצר."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"הבקשה לייצוא ה-vCard נדחתה. נסה שוב מאוחר יותר."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"איש קשר"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"קובצי ה-vCard נשמרים כקבצים באחסון מקומי זמני. הייבוא בפועל יחל בקרוב."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"לא ניתן לייבא את ה-vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"איש הקשר התקבל באמצעות NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"לייצא את אנשי הקשר?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"הופך לקובץ שמור"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"מייבא <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"הגדרות"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"שתף אנשי קשר גלויים"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"יבא/יצא אנשי קשר"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"יבוא אנשי קשר"</string>
+ <string name="share_error" msgid="948429331673358107">"לא ניתן לשתף איש קשר זה."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"חפש"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"אנשי קשר להצגה"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"אנשי קשר להצגה"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"מועדפים"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"אין אנשי קשר."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"מחק אנשי קשר קבועים"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"בחר כרטיס SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"ייבוא/ייצוא"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"מספרים חסומים"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"באמצעות <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> באמצעות <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"נקה חיפוש"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ja/donottranslate_config.xml b/res/values-ja/donottranslate_config.xml
new file mode 100644
index 0000000..ff8a8eb
--- /dev/null
+++ b/res/values-ja/donottranslate_config.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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>
+ <!-- If true, an option is shown in Display Options UI to choose a sort order -->
+ <bool name="config_sort_order_user_changeable">false</bool>
+
+ <!-- If true, the default sort order is primary (i.e. by given name) -->
+ <bool name="config_default_sort_order_primary">true</bool>
+
+ <!-- If true, an option is shown in Display Options UI to choose a name display order -->
+ <bool name="config_display_order_user_changeable">false</bool>
+
+ <!-- If true, the default sort order is primary (i.e. by given name) -->
+ <bool name="config_default_display_order_primary">true</bool>
+
+ <!-- If true, the order of name fields in the editor is primary (i.e. given name first) -->
+ <bool name="config_editor_field_order_primary">false</bool>
+
+ <!-- If true, phonetic name is included in the contact editor by default -->
+ <bool name="config_editor_include_phonetic_name">true</bool>
+</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 1857827..1b7e3da 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"デフォルトに設定"</string>
<string name="clear_default" msgid="7193185801596678067">"デフォルトを解除"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"テキストをコピーしました"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"変更を破棄して編集を終了しますか?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"変更を破棄しますか?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"破棄"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"編集を続ける"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"キャンセル"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"連絡先を検索"</string>
<string name="title_edit_group" msgid="8602752287270586734">"連絡先の削除"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"概要"</string>
<string name="send_message" msgid="8938418965550543196">"メッセージの送信"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"個人用コピーを作成しています..."</string>
- <string name="yesterday" msgid="6840858548955018569">"昨日"</string>
<string name="tomorrow" msgid="6241969467795308581">"明日"</string>
<string name="today" msgid="8041090779381781781">"今日"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"今日の<xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"メッセージ"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"リストを整理しましょう"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"重複を修正できるほか、連絡先をラベル別にグループ化することができます"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"テキストをコピーしました"</string>
+ <string name="copy_text" msgid="3257145021583508761">"クリップボードにコピー"</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="8563753966926932052">"発信"</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="5745314124619636674">"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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"電話に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="3888842199855843152">"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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"よく使う連絡先をクリアしますか?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"よく使う連絡先をクリアしています…"</string>
+ <string name="status_available" msgid="5586870015822828392">"オンライン"</string>
+ <string name="status_away" msgid="1838861100379804730">"不在"</string>
+ <string name="status_busy" msgid="9147992455450257136">"取り込み中"</string>
+ <string name="contactsList" msgid="8661624236494819731">"連絡先"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"その他"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"ディレクトリ"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"すべての連絡先"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"検索しています..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g>件以上見つかりました。"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"連絡先はありません"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g>件見つかりました</item>
+ <item quantity="one">1件見つかりました</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g>さんのクイックコンタクト"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(名前なし)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"よく使う連絡先"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"連絡先を表示"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"電話番号のあるすべての連絡先"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"更新情報を表示"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"名前"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"ニックネーム"</string>
+ <string name="full_name" msgid="6602579550613988977">"名前"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"よみがな"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"ミドルネームのよみがな"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"電話番号"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"メール"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"住所"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"チャット"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"所属"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"関係"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"テキストメッセージ"</string>
+ <string name="postal_address" msgid="8765560217149624536">"住所"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"会社"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"役職"</string>
+ <string name="label_notes" msgid="8337354953278341042">"メモ"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"ウェブサイト"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"メール送信"</string>
+ <string name="email_custom" msgid="7548003991586214105">"<xliff:g id="CUSTOM">%s</xliff:g>にメール"</string>
+ <string name="email" msgid="5668400997660065897">"メール"</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="map_home" msgid="1243547733423343982">"自宅の住所を表示"</string>
+ <string name="map_work" msgid="1360474076921878088">"勤務先の住所を表示"</string>
+ <string name="map_other" msgid="3817820803587012641">"住所を表示"</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="description_minus_button" msgid="6908099247930477551">"削除"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"名前フィールドの展開/折りたたみ"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"すべての連絡先"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"スター付き"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"カスタマイズ"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"連絡先"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"その他すべての連絡先"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"すべての連絡先"</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_warn_remove_ungrouped" msgid="8872290721676651414">"「<xliff:g id="GROUP">%s</xliff:g>」を同期から除外すると、グループに含まれない連絡先もすべて同期から除外されます。"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"表示オプションを保存中..."</string>
+ <string name="menu_done" msgid="796017761764190697">"完了"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"キャンセル"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"SIMカードからインポート"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g>のインポートをキャンセルしますか?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g>のエクスポートをキャンセルしますか?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCardインポート/エクスポート取り消し不可"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"不明なエラーです。"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"「<xliff:g id="FILE_NAME">%s</xliff:g>」を開けませんでした: <xliff:g id="EXACT_REASON">%s</xliff:g>。"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"エクスポータを起動できませんでした: 「<xliff:g id="EXACT_REASON">%s</xliff:g>」。"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"エクスポートできる連絡先がありません。"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"エクスポート中にエラーが発生しました: 「<xliff:g id="EXACT_REASON">%s</xliff:g>」。"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"ファイル名(必須)が長すぎます(「<xliff:g id="FILENAME">%s</xliff:g>」)。"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"送受信エラー"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"メモリが不足しています。ファイルが大きすぎる可能性があります。"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"予期しない理由によりvCardを解析できませんでした。"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"このフォーマットには対応していません。"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"指定されたvCardファイルのメタ情報を取得できませんでした。"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"1つ以上のファイルをインポートできませんでした(%s)。"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g>のエクスポートが完了しました。"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g>のエクスポートをキャンセルしました。"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"連絡先データのエクスポート"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"データベース情報を取得できませんでした。"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"エクスポートできる連絡先がありません。モバイル端末に連絡先がある場合でも、データプロバイダによってはモバイル端末から連絡先をエクスポートできないことがあります。"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCardコンポーザーが正しく起動しませんでした。"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"エクスポート失敗"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"連絡先データはエクスポートされませんでした。\n理由: 「<xliff:g id="FAIL_REASON">%s</xliff:g>」"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g>をインポート中"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCardデータを読み取れませんでした"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCardデータの読取をキャンセルしました"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard<xliff:g id="FILENAME">%s</xliff:g>のインポートが終了しました"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g>のインポートをキャンセルしました"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g>はまもなくインポートされます。"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"ファイルはまもなくインポートされます。"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCardのインポートリクエストは拒否されました。しばらくしてからもう一度お試しください。"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g>はまもなくエクスポートされます。"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCardのエクスポートリクエストは拒否されました。しばらくしてからもう一度お試しください。"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"連絡先"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCardをローカル一時ストレージにキャッシュしています。まもなくインポート処理を開始します。"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCardをインポートできませんでした。"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC受信の連絡先"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"エクスポートしますか?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"キャッシュしています"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>件(<xliff:g id="NAME">%s</xliff:g>)をインポート中"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"設定"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"表示可能な連絡先を共有"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"連絡先のインポート/エクスポート"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"連絡先のインポート"</string>
+ <string name="share_error" msgid="948429331673358107">"この連絡先は共有できません。"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"検索"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"表示する連絡先"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"表示する連絡先"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"お気入り"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"連絡先はありません。"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"よく使う連絡先のクリア"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIMカードを選択"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"インポート/エクスポート"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"ブロックした番号"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g>経由"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g>、<xliff:g id="SOURCE">%2$s</xliff:g>経由"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"検索をクリア"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index 66ed650..93f9155 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"ნაგულისხმევად დაყენება"</string>
<string name="clear_default" msgid="7193185801596678067">"ნაგულისხმევის წაშლა"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"კოპირებული ტექსტი"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"გსურთ ცვლილებების გაუქმება და რედაქტირებიდან გასვლა?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"გაუქმდეს ცვლილებები?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"გაუქმება"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"რედაქტირების გაგრძელება"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"გაუქმება"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"კონტაქტების ძიება"</string>
<string name="title_edit_group" msgid="8602752287270586734">"კონტაქტების წაშლა"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"შესახებ"</string>
<string name="send_message" msgid="8938418965550543196">"შეტყობინების გაგზავნა"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"პირადი ასლის შექმნა…"</string>
- <string name="yesterday" msgid="6840858548955018569">"გუშინ"</string>
<string name="tomorrow" msgid="6241969467795308581">"ხვალ"</string>
<string name="today" msgid="8041090779381781781">"დღეს"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"დღეს <xliff:g id="TIME_INTERVAL">%s</xliff:g>-ზე"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"შეტყობინებები"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"მოახდინეთ თქვენი სიის ორგანიზება"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"დუბლიკატებისა და ჯგუფის კონტაქტების გასუფთავება ლეიბლის მიხედვით"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"კოპირებული ტექსტი"</string>
+ <string name="copy_text" msgid="3257145021583508761">"კოპირება გაცვლის ბუფერში"</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="8563753966926932052">"დარეკვა"</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="5745314124619636674">"დარეკვა ფაქსზე"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"ტექსტური შეტყობინების გაგზავნა"</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="3888842199855843152">"ტექსტური შეტყობინების გაგზავნა ფაქსზე"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"გსურთ ხშირი კონტაქტების წაშლა?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"ხშირი კონტაქტები იშლება…"</string>
+ <string name="status_available" msgid="5586870015822828392">"ხელმისაწვდომი"</string>
+ <string name="status_away" msgid="1838861100379804730">"გასული"</string>
+ <string name="status_busy" msgid="9147992455450257136">"დაკავებული"</string>
+ <string name="contactsList" msgid="8661624236494819731">"კონტაქტები"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"სხვა"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"კატალოგი"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"ყველა კონტაქტი"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"ძიება..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"ნაპოვნია <xliff:g id="COUNT">%d</xliff:g>-ზე მეტი."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"კონტაქტები არ არის"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> მოიძებნა</item>
+ <item quantity="one">1 მოიძებნა</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"სწრაფი კონტაქტი <xliff:g id="NAME">%1$s</xliff:g>-თან"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(სახელის გარეშე)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"ხშირი კონტაქტები"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"კონტაქტის ნახვა"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"ყველა ტელეფონის ნომრიანი კონტაქტი"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"განახლებების ნახვა"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"სახელი"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"მეტსახელი"</string>
+ <string name="full_name" msgid="6602579550613988977">"სახელი"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"სახელის ტრანსკრიფცია"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"მეორე სახელის ტრანსკრიფცია"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"ტელეფონი"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"ელფოსტა"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"მისამართი"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"ორგანიზაცია"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"ურთიერთობა"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"ტექსტური შეტყობინება"</string>
+ <string name="postal_address" msgid="8765560217149624536">"მისამართი"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"კომპანია"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"სათაური"</string>
+ <string name="label_notes" msgid="8337354953278341042">"შენიშვნები"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"ვებ-საიტი"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"ელფოსტის გაგზავნა"</string>
+ <string name="email_custom" msgid="7548003991586214105">"ელფოსტის გაგზავნა <xliff:g id="CUSTOM">%s</xliff:g>-ზე"</string>
+ <string name="email" msgid="5668400997660065897">"ელფოსტის გაგზავნა"</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">"ZIP-კოდი"</string>
+ <string name="postal_country" msgid="7638264508416368690">"ქვეყანა"</string>
+ <string name="map_home" msgid="1243547733423343982">"სახლის მისამართის ნახვა"</string>
+ <string name="map_work" msgid="1360474076921878088">"სამსახურის მისამართის ნახვა"</string>
+ <string name="map_other" msgid="3817820803587012641">"მისამართის ნახვა"</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="description_minus_button" msgid="6908099247930477551">"წაშლა"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"სახელთა ველების გაშლა ან აკეცვა"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"ყველა კონტაქტი"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"ვარსკვლავიანი"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"მორგება"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"კონტაქტი"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"ყველა სხვა კონტაქტი"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"ყველა კონტაქტი"</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_warn_remove_ungrouped" msgid="8872290721676651414">"სინქრონიზაციიდან „<xliff:g id="GROUP">%s</xliff:g>“-ის ამოშლა წაშლის ყველა დაუჯგუფებელ კონტაქტს."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"ეკრანის პარამეტრების შენახვა…"</string>
+ <string name="menu_done" msgid="796017761764190697">"დასრულდა"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"გაუქმება"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM ბარათიდან იმპორტი"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g>-ის იმპორტის გაუქმება?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"გსურთ <xliff:g id="FILENAME">%s</xliff:g>-ის ექსპორტის გაუქმება?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard-ის იმპორტი/ექსპორტი ვერ მოხერხდა"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"უცნობი შეცდომა."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"„<xliff:g id="FILE_NAME">%s</xliff:g>“ ვერ გაიხსნა: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"ექსპორტერის გაშვება ვერ მოხერხდა: „<xliff:g id="EXACT_REASON">%s</xliff:g>“."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"ექსპორტირებადი კონტაქტი არ არსებობს."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"ექსპორტი ვერ მოხერხდა: „<xliff:g id="EXACT_REASON">%s</xliff:g>“."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"მოთხოვნილი ფაილის სახელი ძალიან გრძელია („<xliff:g id="FILENAME">%s</xliff:g>“)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O შეცდომა"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"მეხსიერება არასაკმარისია. შესაძლოა ფაილი ძალიან დიდია."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"vCard ფაილის გარჩევა ვერ მოხერხდა რომელიღაც მოულოდნელი მიზეზით."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"ეს ფორმატი მხარდაუჭერელია."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"მოცემული vCard ფაილ(ებ)ის მეტა ინფორმაციის შეგროვება ვერ მოხერხდა."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"ერთი ან მეტი ფაილის იმპორტი ვერ მოხერხდა (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g>-ის ექსპორტი დასრულდა."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g>-ის ექსპორტი გაუქმდა."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"კონტაქტების მონაცემთა ექსპორტი"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"მონაცემთა ბაზის ინფორმაციის მიღება ვერ მოხერხდა."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"ექსპორტირებადი კონტაქტები არ მოიპოვება. თუ კონტაქტები ნამდვილად არის თქვენს ტელეფონში, შესაძლოა ზოგიერთი მონაცემთა მომწოდებელი არ იძლევა ტელეფონიდან მათი ექსპორტის უფლებას."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard კომპოზიტორი გაშვებულია არასწორად."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"ექსპორტი ჩაიშალა."</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"კონტაქტების მონაცემები არ არის ექსპორტირებული.\nმიზეზი: „<xliff:g id="FAIL_REASON">%s</xliff:g>“"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"იმპორტირდება <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard მონაცემთა წაკითხვა ვერ მოხერხდა"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard მონაცემთა წაკითხვა გაუქმდა"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g>-ის იმპორტი დასრულდა"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g>-ის იმპორტი გაუქმდა"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> მალე იმპორტირდება."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"ამ ფაილის იმპორტი მალე შესრულდება."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard-ის იმპორტის მოთხოვნა უარყოფილია. სცადეთ მოგვიანებით."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> მალე ექსპორტირდება."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard-ის ექსპორტის მოთხოვნა უარყოფილია. სცადეთ მოგვიანებით."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"კონტაქტი"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"მიმდინარეობს vCard ფაილ(ებ)ის ქეშირება დროებით ადგილობრივ მეხსიერებაში. ფაქტიური იმპორტი დაიწყება მალე."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard-ის იმპორტი ვერ მოხერხდა."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"კონტაქტი NFC-ით"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"გსურთ კონტაქტების ექსპორტი?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"ქეშირება"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"მიმდინარეობს იმპორტი <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"პარამეტრები"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"ხილული კონტაქტების გაზიარება"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"კონტაქტების იმპორტი/ექსპორტი"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"კონტაქტების იმპორტი"</string>
+ <string name="share_error" msgid="948429331673358107">"ამ კონტაქტის გაზიარება შეუძლებელია."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"ძიება"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"საჩვენებელი კონტაქტები"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"საჩვენებელი კონტაქტები"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"რჩეულები"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"კონტაქტები არ არის."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"ხშირი კონტაქტების წაშლა"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"აირჩიეთ SIM ბარათი"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"იმპორტი/ექსპორტი"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"დაბლოკილი ნომრები"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g>-ის საშუალებით"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="SOURCE">%2$s</xliff:g>-ის მეშვეობით"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"ძიების გასუფთავება"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
index 500727e..22cd715 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk-rKZ/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Бастапқы ретінде орнату"</string>
<string name="clear_default" msgid="7193185801596678067">"Бастапқыны өшіру"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Мәтін көшірмесі жасалды"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Өзгертулерді алып тастап, өңдеуден шығу керек пе?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Өзгертулерді алып тастау қажет пе?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Алып тастау"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Өңдеуді жалғастыру"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Бас тарту"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Контактілерді іздеу"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Контактілерді жою"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Туралы"</string>
<string name="send_message" msgid="8938418965550543196">"Хабарды жіберу"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Жеке көшірме жасау…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Кеше"</string>
<string name="tomorrow" msgid="6241969467795308581">"Ертең"</string>
<string name="today" msgid="8041090779381781781">"Бүгін"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Бүгін, <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,505 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Хабарлар"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Тізіміңізді реттеңіз"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Көшірмелерді өшіріп, контактілерді белгілері бойынша топтаңыз"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Мәтін көшірмесі жасалды"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Аралық сақтағышқа көшіру"</string>
+ <!-- no translation found for call_custom (7756571794763171802) -->
+ <skip />
+ <!-- no translation found for call_home (1990519474420545392) -->
+ <skip />
+ <!-- no translation found for call_mobile (7502236805487609178) -->
+ <skip />
+ <!-- no translation found for call_work (5328785911463744028) -->
+ <skip />
+ <!-- no translation found for call_fax_work (7467763592359059243) -->
+ <skip />
+ <!-- no translation found for call_fax_home (8342175628887571876) -->
+ <skip />
+ <!-- no translation found for call_pager (9003902812293983281) -->
+ <skip />
+ <!-- no translation found for call_other (8563753966926932052) -->
+ <skip />
+ <!-- no translation found for call_callback (1910165691349426858) -->
+ <skip />
+ <!-- no translation found for call_car (3280537320306436445) -->
+ <skip />
+ <!-- no translation found for call_company_main (6105120947138711257) -->
+ <skip />
+ <!-- no translation found for call_isdn (1541590690193403411) -->
+ <skip />
+ <!-- no translation found for call_main (6082900571803441339) -->
+ <skip />
+ <!-- no translation found for call_other_fax (5745314124619636674) -->
+ <skip />
+ <!-- no translation found for call_radio (8296755876398357063) -->
+ <skip />
+ <!-- no translation found for call_telex (2223170774548648114) -->
+ <skip />
+ <!-- no translation found for call_tty_tdd (8951266948204379604) -->
+ <skip />
+ <!-- no translation found for call_work_mobile (8707874281430105394) -->
+ <skip />
+ <!-- no translation found for call_work_pager (3419348514157949008) -->
+ <skip />
+ <!-- no translation found for call_assistant (2141641383068514308) -->
+ <skip />
+ <!-- no translation found for call_mms (6274041545876221437) -->
+ <skip />
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <!-- no translation found for sms_custom (5932736853732191825) -->
+ <skip />
+ <!-- no translation found for sms_home (7524332261493162995) -->
+ <skip />
+ <!-- no translation found for sms_mobile (5200107250451030769) -->
+ <skip />
+ <!-- no translation found for sms_work (2269624156655267740) -->
+ <skip />
+ <!-- no translation found for sms_fax_work (8028189067816907075) -->
+ <skip />
+ <!-- no translation found for sms_fax_home (9204042076306809634) -->
+ <skip />
+ <!-- no translation found for sms_pager (7730404569637015192) -->
+ <skip />
+ <!-- no translation found for sms_other (806127844607642331) -->
+ <skip />
+ <!-- no translation found for sms_callback (5004824430094288752) -->
+ <skip />
+ <!-- no translation found for sms_car (7444227058437359641) -->
+ <skip />
+ <!-- no translation found for sms_company_main (118970873419678087) -->
+ <skip />
+ <!-- no translation found for sms_isdn (8153785037515047845) -->
+ <skip />
+ <!-- no translation found for sms_main (8621625784504541679) -->
+ <skip />
+ <!-- no translation found for sms_other_fax (3888842199855843152) -->
+ <skip />
+ <!-- no translation found for sms_radio (3329166673433967820) -->
+ <skip />
+ <!-- no translation found for sms_telex (9034802430065267848) -->
+ <skip />
+ <!-- no translation found for sms_tty_tdd (6782284969132531532) -->
+ <skip />
+ <!-- no translation found for sms_work_mobile (2459939960512702560) -->
+ <skip />
+ <!-- no translation found for sms_work_pager (5566924423316960597) -->
+ <skip />
+ <!-- no translation found for sms_assistant (2773424339923116234) -->
+ <skip />
+ <!-- no translation found for sms_mms (4069352461380762677) -->
+ <skip />
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation_title (766292372438450432) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <!-- no translation found for clearFrequentsProgress_title (5157001637482794212) -->
+ <skip />
+ <!-- no translation found for status_available (5586870015822828392) -->
+ <skip />
+ <!-- no translation found for status_away (1838861100379804730) -->
+ <skip />
+ <!-- no translation found for status_busy (9147992455450257136) -->
+ <skip />
+ <string name="contactsList" msgid="8661624236494819731">"Контактілер"</string>
+ <!-- no translation found for local_invisible_directory (6046691709127661065) -->
+ <skip />
+ <!-- no translation found for directory_search_label (1887759056597975053) -->
+ <skip />
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <!-- no translation found for local_search_label (2551177578246113614) -->
+ <skip />
+ <string name="search_results_searching" msgid="3984833028938569930">"Іздеуде…"</string>
+ <!-- no translation found for foundTooManyContacts (5163335650920020220) -->
+ <skip />
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Контактілер жоқ"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> табылды</item>
+ <item quantity="one">1 табылды</item>
+ </plurals>
+ <!-- no translation found for description_quick_contact_for (6737516415168327789) -->
+ <skip />
+ <!-- no translation found for missing_name (8745511583852904385) -->
+ <skip />
+ <!-- no translation found for favoritesFrequentContacted (6184232487472425690) -->
+ <skip />
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Контактіні көру"</string>
+ <!-- no translation found for list_filter_phones (735313795643493365) -->
+ <skip />
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <!-- no translation found for view_updates_from_group (1782685984905600034) -->
+ <skip />
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <!-- no translation found for nameLabelsGroup (2034640839640477827) -->
+ <skip />
+ <!-- no translation found for nicknameLabelsGroup (2891682101053358010) -->
+ <skip />
+ <!-- no translation found for full_name (6602579550613988977) -->
+ <skip />
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <!-- no translation found for name_prefix (59756378548779822) -->
+ <skip />
+ <!-- no translation found for name_middle (8467433655992690326) -->
+ <skip />
+ <!-- no translation found for name_suffix (3855278445375651441) -->
+ <skip />
+ <!-- no translation found for name_phonetic (4259595234312430484) -->
+ <skip />
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <!-- no translation found for name_phonetic_middle (8643721493320405200) -->
+ <skip />
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <!-- no translation found for phoneLabelsGroup (6468091477851199285) -->
+ <skip />
+ <!-- no translation found for emailLabelsGroup (8389931313045344406) -->
+ <skip />
+ <!-- no translation found for postalLabelsGroup (3487738141112589324) -->
+ <skip />
+ <!-- no translation found for imLabelsGroup (3898238486262614027) -->
+ <skip />
+ <!-- no translation found for organizationLabelsGroup (2478611760751832035) -->
+ <skip />
+ <!-- no translation found for relationLabelsGroup (1854373894284572781) -->
+ <skip />
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <!-- no translation found for sms (1756857139634224222) -->
+ <skip />
+ <!-- no translation found for postal_address (8765560217149624536) -->
+ <skip />
+ <!-- no translation found for ghostData_company (5414421120553765775) -->
+ <skip />
+ <!-- no translation found for ghostData_title (7496735200318496110) -->
+ <skip />
+ <!-- no translation found for label_notes (8337354953278341042) -->
+ <skip />
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <!-- no translation found for websiteLabelsGroup (4202998982804009261) -->
+ <skip />
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <!-- no translation found for email_home (8573740658148184279) -->
+ <skip />
+ <!-- no translation found for email_mobile (2042889209787989814) -->
+ <skip />
+ <!-- no translation found for email_work (2807430017302722689) -->
+ <skip />
+ <!-- no translation found for email_other (3454004077967657109) -->
+ <skip />
+ <!-- no translation found for email_custom (7548003991586214105) -->
+ <skip />
+ <!-- no translation found for email (5668400997660065897) -->
+ <skip />
+ <!-- no translation found for postal_street (8133143961580058972) -->
+ <skip />
+ <!-- no translation found for postal_pobox (4431938829180269821) -->
+ <skip />
+ <!-- no translation found for postal_neighborhood (1450783874558956739) -->
+ <skip />
+ <!-- no translation found for postal_city (6597491300084895548) -->
+ <skip />
+ <!-- no translation found for postal_region (6045263193478437672) -->
+ <skip />
+ <!-- no translation found for postal_postcode (572136414136673751) -->
+ <skip />
+ <!-- no translation found for postal_country (7638264508416368690) -->
+ <skip />
+ <!-- no translation found for map_home (1243547733423343982) -->
+ <skip />
+ <!-- no translation found for map_work (1360474076921878088) -->
+ <skip />
+ <!-- no translation found for map_other (3817820803587012641) -->
+ <skip />
+ <!-- no translation found for map_custom (6184363799976265281) -->
+ <skip />
+ <!-- no translation found for chat_aim (2588492205291249142) -->
+ <skip />
+ <!-- no translation found for chat_msn (8041633440091073484) -->
+ <skip />
+ <!-- no translation found for chat_yahoo (6629211142719943666) -->
+ <skip />
+ <!-- no translation found for chat_skype (1210045020427480566) -->
+ <skip />
+ <!-- no translation found for chat_qq (4294637812847719693) -->
+ <skip />
+ <!-- no translation found for chat_gtalk (981575737258117697) -->
+ <skip />
+ <!-- no translation found for chat_icq (8438405386153745775) -->
+ <skip />
+ <!-- no translation found for chat_jabber (7561444230307829609) -->
+ <skip />
+ <!-- no translation found for chat (9025361898797412245) -->
+ <skip />
+ <!-- no translation found for description_minus_button (6908099247930477551) -->
+ <skip />
+ <!-- no translation found for expand_collapse_name_fields_description (8682630859539604311) -->
+ <skip />
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <!-- no translation found for list_filter_all_accounts (8908683398914322369) -->
+ <skip />
+ <!-- no translation found for list_filter_all_starred (5031734941601931356) -->
+ <skip />
+ <!-- no translation found for list_filter_customize (4789963356004169321) -->
+ <skip />
+ <!-- no translation found for list_filter_single (5871400283515893087) -->
+ <skip />
+ <!-- no translation found for display_ungrouped (6885954210243119591) -->
+ <skip />
+ <!-- no translation found for display_all_contacts (2031647544742889505) -->
+ <skip />
+ <!-- no translation found for menu_sync_remove (3266725887008450161) -->
+ <skip />
+ <!-- no translation found for dialog_sync_add (8267045393119375803) -->
+ <skip />
+ <!-- no translation found for display_more_groups (2682547080423434170) -->
+ <skip />
+ <!-- no translation found for display_warn_remove_ungrouped (8872290721676651414) -->
+ <skip />
+ <!-- no translation found for savingDisplayGroups (2133152192716475939) -->
+ <skip />
+ <!-- no translation found for menu_done (796017761764190697) -->
+ <skip />
+ <!-- no translation found for menu_doNotSave (58593876893538465) -->
+ <skip />
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <!-- no translation found for import_from_sim (3859272228033941659) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <!-- no translation found for cancel_import_confirmation_message (3929951040347726757) -->
+ <skip />
+ <!-- no translation found for cancel_export_confirmation_message (1995462401949262638) -->
+ <skip />
+ <!-- no translation found for cancel_vcard_import_or_export_failed (6139900383366166706) -->
+ <skip />
+ <!-- no translation found for fail_reason_unknown (1714092345030570863) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_open_file (2067725459821997463) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_initialize_exporter (707260459259688510) -->
+ <skip />
+ <!-- no translation found for fail_reason_no_exportable_contact (8728506011371262065) -->
+ <skip />
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <!-- no translation found for fail_reason_error_occurred_during_export (3018855323913649063) -->
+ <skip />
+ <!-- no translation found for fail_reason_too_long_filename (3393764245254738333) -->
+ <skip />
+ <!-- no translation found for fail_reason_io_error (6748358842976073255) -->
+ <skip />
+ <!-- no translation found for fail_reason_low_memory_during_import (875222757734882898) -->
+ <skip />
+ <!-- no translation found for fail_reason_vcard_parse_error (888263542360355784) -->
+ <skip />
+ <!-- no translation found for fail_reason_not_supported (8219562769267148825) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_collect_vcard_meta_info (6427931733267328564) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title (4767045779458185251) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_canceled_title (2652222370493306887) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <!-- no translation found for composer_failed_to_get_database_infomation (1765944280846236723) -->
+ <skip />
+ <!-- no translation found for composer_has_no_exportable_contact (3296493229040294335) -->
+ <skip />
+ <!-- no translation found for composer_not_initialized (2321648986367005254) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_title (4892358112409576342) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_message (4938527850142003141) -->
+ <skip />
+ <!-- no translation found for importing_vcard_description (4245275224298571351) -->
+ <skip />
+ <!-- no translation found for reading_vcard_failed_title (4251647443358422855) -->
+ <skip />
+ <!-- no translation found for reading_vcard_canceled_title (1925216585981542019) -->
+ <skip />
+ <!-- no translation found for importing_vcard_finished_title (3341541727268747967) -->
+ <skip />
+ <!-- no translation found for importing_vcard_canceled_title (2147475978165599336) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message (2804911199145873396) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message_with_default_name (1022969530654129470) -->
+ <skip />
+ <!-- no translation found for vcard_import_request_rejected_message (2890471184508516011) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message (2210241345252081463) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <!-- no translation found for vcard_export_request_rejected_message (2844874826431327531) -->
+ <skip />
+ <!-- no translation found for vcard_unknown_filename (7171709890959915954) -->
+ <skip />
+ <!-- no translation found for caching_vcard_message (4926308675041506756) -->
+ <skip />
+ <!-- no translation found for vcard_import_failed (5223531255894842406) -->
+ <skip />
+ <!-- no translation found for nfc_vcard_file_name (2823095213265993609) -->
+ <skip />
+ <!-- no translation found for confirm_export_title (6834385377255286349) -->
+ <skip />
+ <!-- no translation found for caching_vcard_title (1226272312940516605) -->
+ <skip />
+ <!-- no translation found for progress_notifier_message (2311011466908220528) -->
+ <skip />
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Параметрлер"</string>
+ <!-- no translation found for share_visible_contacts (890150378880783797) -->
+ <skip />
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <!-- no translation found for dialog_import_export (4360648034889921624) -->
+ <skip />
+ <!-- no translation found for dialog_import (2431698729761448759) -->
+ <skip />
+ <!-- no translation found for share_error (948429331673358107) -->
+ <skip />
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <!-- no translation found for menu_search (9147752853603483719) -->
+ <skip />
+ <!-- no translation found for menu_contacts_filter (2165153460860262501) -->
+ <skip />
+ <!-- no translation found for activity_title_contacts_filter (8275542497615516969) -->
+ <skip />
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <!-- no translation found for contactsFavoritesLabel (8417039765586853670) -->
+ <skip />
+ <!-- no translation found for listTotalAllContactsZero (5513001821794568211) -->
+ <skip />
+ <!-- no translation found for menu_clear_frequents (7688250191932838833) -->
+ <skip />
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM картасын таңдау"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <!-- no translation found for menu_import_export (26217871113229507) -->
+ <skip />
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Бөгелген нөмірлер"</string>
+ <!-- no translation found for contact_status_update_attribution (752179367353018597) -->
+ <skip />
+ <!-- no translation found for contact_status_update_attribution_with_date (7358045508107825068) -->
+ <skip />
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Іздеуді өшіру"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
index c4d77fa..bde886c 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km-rKH/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"កំណត់លំនាំដើម"</string>
<string name="clear_default" msgid="7193185801596678067">"សម្អាតលំនាំដើម"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"បានចម្លងអត្ថបទ"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"បោះបង់ការប្ដូររបស់អ្នក ហើយបញ្ឈប់ការកែសម្រួលមែនទេ?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"បោះបង់ការផ្លាស់ប្ដូរដែរ ឬទេ?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"បោះបង់"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"នៅបន្តកែសម្រួល"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"បោះបង់"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"ស្វែងរកទំនាក់ទំនង"</string>
<string name="title_edit_group" msgid="8602752287270586734">"ដកទំនាក់ទំនងចេញ"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"អំពី"</string>
<string name="send_message" msgid="8938418965550543196">"ផ្ញើសារ"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"កំពុងបង្កើតច្បាប់ចម្លងផ្ទាល់ខ្លួន..."</string>
- <string name="yesterday" msgid="6840858548955018569">"ម្សិលមិញ"</string>
<string name="tomorrow" msgid="6241969467795308581">"ស្អែក"</string>
<string name="today" msgid="8041090779381781781">"ថ្ងៃនេះ"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"ថ្ងៃនេះនៅ <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"សារ"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"រៀបចំបញ្ជីរបស់អ្នក"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"សម្អាតទំនាក់ទំនងដែលស្ទួនគ្នា & ដាក់ជាក្រុមតាមស្លាក"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"បានចម្លងអត្ថបទ"</string>
+ <string name="copy_text" msgid="3257145021583508761">"ចម្លងទៅក្ដារតម្បៀតខ្ទាស់"</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="8563753966926932052">"ហៅ"</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="5745314124619636674">"ហៅទៅទូរសារ"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"អត្ថបទ"</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="3888842199855843152">"អត្ថបទទូរសារ"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"សម្អាតទំនាក់ទំនងញឹកញាប់?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"កំពុងសម្អាតទំនាក់ទំនងញឹកញាប់..."</string>
+ <string name="status_available" msgid="5586870015822828392">"ទំនេរ"</string>
+ <string name="status_away" msgid="1838861100379804730">"ចាកឆ្ងាយ"</string>
+ <string name="status_busy" msgid="9147992455450257136">"រវល់"</string>
+ <string name="contactsList" msgid="8661624236494819731">"ទំនាក់ទំនង"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"ផ្សេងៗ"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"ថត"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"ទំនាក់ទំនងទាំងអស់"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"កំពុងរក..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"បានរកឃើញច្រើនជាង <xliff:g id="COUNT">%d</xliff:g> ។"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"មិនមានទំនាក់ទំនង"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">បានរកឃើញ <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="one">បានរកឃើញ 1</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"ទំនាក់ទំនងរហ័សសម្រាប់ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(គ្មានឈ្មោះ)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"បានទាក់ទងញឹកញាប់"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"មើលទំនាក់ទំនង"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"ទំនាក់ទំនងទាំងអស់ដែលមានលេខទូរស័ព្ទ"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"មើលបច្ចុប្បន្នភាព"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"ឈ្មោះ"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"សម្មតិនាម"</string>
+ <string name="full_name" msgid="6602579550613988977">"ឈ្មោះ"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"សូរស័ព្ទឈ្មោះ"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"សូរស័ព្ទឈ្មោះកណ្ដាល"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"ទូរស័ព្ទ"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"អ៊ីមែល"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"អាសយដ្ឋាន"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"ស្ថាប័ន"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"ចំណងទាក់ទង"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"សារអត្ថបទ"</string>
+ <string name="postal_address" msgid="8765560217149624536">"អាសយដ្ឋាន"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"ក្រុមហ៊ុន"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"ចំណងជើង"</string>
+ <string name="label_notes" msgid="8337354953278341042">"ចំណាំ"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"តំបន់បណ្ដាញ"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"អ៊ីមែល"</string>
+ <string name="email_custom" msgid="7548003991586214105">"អ៊ីមែល <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"អ៊ីមែល"</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="map_home" msgid="1243547733423343982">"មើលអាសយដ្ឋានផ្ទះ"</string>
+ <string name="map_work" msgid="1360474076921878088">"មើលអាសយដ្ឋានការងារ"</string>
+ <string name="map_other" msgid="3817820803587012641">"មើលអាសយដ្ឋាន"</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="description_minus_button" msgid="6908099247930477551">"លុប"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"ពង្រីក ឬបង្រួមវាលឈ្មោះ"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"ទំនាក់ទំនងទាំងអស់"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"បានដាក់ផ្កាយ"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"ប្ដូរតាមតម្រូវការ"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"ទំនាក់ទំនង"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"ទំនាក់ទំនងទាំងអស់ផ្សេងទៀត"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"ទំនាក់ទំនងទាំងអស់"</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_warn_remove_ungrouped" msgid="8872290721676651414">"ការលុប \"<xliff:g id="GROUP">%s</xliff:g>\" ចេញពីសមកាលកម្មវាក៏នឹងលុបទំនាក់ទំនងដែលមិននៅក្នុងក្រុមចេញពីសមកាលកម្មផងដែរ។"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"កំពុងរក្សាទុកជម្រើសបង្ហាញ..."</string>
+ <string name="menu_done" msgid="796017761764190697">"រួចរាល់"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"បោះបង់"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"នាំចូលពីស៊ីមកាត"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"បោះបង់ការនាំចូល <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"បោះបង់ការនាំចេញ <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"មិនអាចបោះបង់ការនាំចេញ/នាំចូល vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"មិនស្គាល់កំហុស។"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"មិនអាចបើក \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g> ។"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"មិនអាចចាប់ផ្ដើមមការនាំចេញ៖ \"<xliff:g id="EXACT_REASON">%s</xliff:g>\" ។"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"មិនមានទំនាក់ទំនងដើម្បីនាំចេញ។"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"មានកំហុសកើតឡើងពេលនាំចេញ៖ \"<xliff:g id="EXACT_REASON">%s</xliff:g>\" ។"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"ឈ្មោះឯកសារដែលបានទាមទារគឺវែងពេក (\"<xliff:g id="FILENAME">%s</xliff:g>\") ។"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"កំហុស I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"អង្គចងចាំមិនគ្រប់គ្រាន់។ ឯកសារប្រហែលជាធំពេក។"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"មិនអាចញែក vCard ដោយសារហេតុផលមិនរំពឹងទុក។"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"មិនគាំទ្រទ្រង់ទ្រាយ។"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"មិនអាចប្រមូលព័ត៌មានមេតារបស់ឯកសារ vCard(s) ដែលបានផ្ដល់។"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"មានឯកសារមួយ ឬច្រើនដែលមិនអាចនាំចូល (%s) ។"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"បានបញ្ចប់ការនាំចេញ <xliff:g id="FILENAME">%s</xliff:g> ។"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"បានបោះបង់ការនាំចេញ <xliff:g id="FILENAME">%s</xliff:g> ។"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"កំពុងនាំចេញព័ត៌មានទំនាក់ទំនង"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"មិនអាចយកព័ត៌មានមូលដ្ឋានទិន្នន័យ។"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"មិនមានទំនាក់ទំនងដើម្បីនាំចេញ។ ប្រសិនបើអ្នកពិតជាមានទំនាក់ទំនងនៅក្នុងកុំព្យូទ័របន្ទះរបស់អ្នកមែន នោះអាចដោយសារតែក្រុមហ៊ុនផ្ដល់ទិន្នន័យមួយចំនួនមិនអនុញ្ញាតឲ្យនាំចេញ។"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"មិនបានចាប់ផ្ដើមកម្មវិធីតែង vCard ដោយត្រឹមត្រូវ។"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"មិនអាចនាំចេញ"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"មិនបាននាំចេញទិន្នន័យទំនាក់ទំនង។\nមូលហេតុ៖ \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"ការនាំចូល <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"មិនអាចអានទិន្នន័យ vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"បានបោះបង់ការអានទិន្នន័យ vCard"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"បានបញ្ចប់ការនាំចូល vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"បានបោះបង់ការនាំចូល <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"នឹងនាំចូល <xliff:g id="FILENAME">%s</xliff:g> ក្នុងពេលឆាប់ៗ។"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"នឹងនាំចូលឯកសារក្នុងពេលឆាប់ៗ។"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"បានបដិសេធសំណើនាំចូល vCard ។ សូមព្យាយាមម្ដងទៀតនៅពេលក្រោយ។"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"នឹងនាំចេញ <xliff:g id="FILENAME">%s</xliff:g> ក្នុងពេលឆាប់ៗ។"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"បានបដិសេធសំណើនាំចេញ vCard ។ សូមព្យាយាមម្ដងទៀតនៅពេលក្រោយ។"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"ទំនាក់ទំនង"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"ការផ្ទុក vCard(s) ទៅកាន់ឧបករណ៍ផ្ទុកបបណ្ដោះអាសន្នមូលដ្ឋាន។ ការនាំចូលពិតប្រាកដនឹងចាប់ផ្ដើមមឆាប់ៗ។"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"មិនអាចនាំចូល vCard ។"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"ទំនាក់ទំនងដែលបានទទួលតាម NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"នាំចេញទំនាក់ទំនង?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"ការផ្ទុកក្នុងឃ្លាំងសម្ងាត់"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"កំពុងនាំចូល <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>៖ <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"ការកំណត់"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"ចែករំលែកទំនាក់ទំនងដែលអាចមើលឃើញ"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"នាំចេញ/នាំចូលទំនាក់ទំនង"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"នាំចូលទំនាក់ទំនង"</string>
+ <string name="share_error" msgid="948429331673358107">"ទំនាក់ទំនងនេះមិនអាចចែករំលែកបានទេ។"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"ស្វែងរក"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"ទំនាក់ទំនងដែលត្រូវបង្ហាញ"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"ទំនាក់ទំនងដែលត្រូវបង្ហាញ"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"សំណព្វ"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"មិនមានទំនាក់ទំនង។"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"សម្អាតញឹកញាប់"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"ជ្រើសស៊ីមកាត"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"នាំចេញ/នាំចូល"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"លេខបានរារាំង"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"តាមរយៈ <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> តាមរយៈ <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"សម្អាតការស្វែងរក"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index 50ea5ac..b0b0c93 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"ಡೀಫಾಲ್ಟ್ ಹೊಂದಿಸಿ"</string>
<string name="clear_default" msgid="7193185801596678067">"ಡಿಫಾಲ್ಟ್ ತೆರವುಗೊಳಿಸಿ"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"ಪಠ್ಯವನ್ನು ನಕಲಿಸಲಾಗಿದೆ"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"ನಿಮ್ಮ ಬದಲಾವಣೆಗಳನ್ನು ತ್ಯಜಿಸಿ ಸಂಪಾದನೆಯನ್ನು ನಿರ್ಗಮಿಸುವುದೇ?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"ಬದಲಾವಣೆಗಳನ್ನು ತ್ಯಜಿಸುವುದೇ?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"ತ್ಯಜಿಸು"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"ಸಂಪಾದಿಸುತ್ತಿರಿ"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"ರದ್ದುಮಾಡು"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"ಸಂಪರ್ಕಗಳನ್ನು ಹುಡುಕಿ"</string>
<string name="title_edit_group" msgid="8602752287270586734">"ಸಂಪರ್ಕಗಳನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"ಕುರಿತು"</string>
<string name="send_message" msgid="8938418965550543196">"ಸಂದೇಶ ಕಳುಹಿಸಿ"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"ವೈಯಕ್ತಿಕ ಪ್ರತಿಯನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
- <string name="yesterday" msgid="6840858548955018569">"ನಿನ್ನೆ"</string>
<string name="tomorrow" msgid="6241969467795308581">"ನಾಳೆ"</string>
<string name="today" msgid="8041090779381781781">"ಇಂದು"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"<xliff:g id="TIME_INTERVAL">%s</xliff:g> ಕ್ಕೆ ಇಂದು"</string>
@@ -342,4 +341,505 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"ಸಂದೇಶಗಳು"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"ನಿಮ್ಮ ಪಟ್ಟಿಯನ್ನು ವ್ಯವಸ್ಥಿತಗೊಳಿಸಿ"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"ನಕಲುಗಳನ್ನು ಸ್ವಚ್ಛಗೊಳಿಸಿ ಮತ್ತು ಸಂಪರ್ಕಗಳನ್ನು ಲೇಬಲ್ಗಳಿಂದ ಗುಂಪು ಮಾಡಿ"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"ಪಠ್ಯವನ್ನು ನಕಲಿಸಲಾಗಿದೆ"</string>
+ <string name="copy_text" msgid="3257145021583508761">"ಕ್ಲಿಪ್ಬೋರ್ಡ್ಗೆ ನಕಲಿಸಿ"</string>
+ <!-- no translation found for call_custom (7756571794763171802) -->
+ <skip />
+ <!-- no translation found for call_home (1990519474420545392) -->
+ <skip />
+ <!-- no translation found for call_mobile (7502236805487609178) -->
+ <skip />
+ <!-- no translation found for call_work (5328785911463744028) -->
+ <skip />
+ <!-- no translation found for call_fax_work (7467763592359059243) -->
+ <skip />
+ <!-- no translation found for call_fax_home (8342175628887571876) -->
+ <skip />
+ <!-- no translation found for call_pager (9003902812293983281) -->
+ <skip />
+ <!-- no translation found for call_other (8563753966926932052) -->
+ <skip />
+ <!-- no translation found for call_callback (1910165691349426858) -->
+ <skip />
+ <!-- no translation found for call_car (3280537320306436445) -->
+ <skip />
+ <!-- no translation found for call_company_main (6105120947138711257) -->
+ <skip />
+ <!-- no translation found for call_isdn (1541590690193403411) -->
+ <skip />
+ <!-- no translation found for call_main (6082900571803441339) -->
+ <skip />
+ <!-- no translation found for call_other_fax (5745314124619636674) -->
+ <skip />
+ <!-- no translation found for call_radio (8296755876398357063) -->
+ <skip />
+ <!-- no translation found for call_telex (2223170774548648114) -->
+ <skip />
+ <!-- no translation found for call_tty_tdd (8951266948204379604) -->
+ <skip />
+ <!-- no translation found for call_work_mobile (8707874281430105394) -->
+ <skip />
+ <!-- no translation found for call_work_pager (3419348514157949008) -->
+ <skip />
+ <!-- no translation found for call_assistant (2141641383068514308) -->
+ <skip />
+ <!-- no translation found for call_mms (6274041545876221437) -->
+ <skip />
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <!-- no translation found for sms_custom (5932736853732191825) -->
+ <skip />
+ <!-- no translation found for sms_home (7524332261493162995) -->
+ <skip />
+ <!-- no translation found for sms_mobile (5200107250451030769) -->
+ <skip />
+ <!-- no translation found for sms_work (2269624156655267740) -->
+ <skip />
+ <!-- no translation found for sms_fax_work (8028189067816907075) -->
+ <skip />
+ <!-- no translation found for sms_fax_home (9204042076306809634) -->
+ <skip />
+ <!-- no translation found for sms_pager (7730404569637015192) -->
+ <skip />
+ <!-- no translation found for sms_other (806127844607642331) -->
+ <skip />
+ <!-- no translation found for sms_callback (5004824430094288752) -->
+ <skip />
+ <!-- no translation found for sms_car (7444227058437359641) -->
+ <skip />
+ <!-- no translation found for sms_company_main (118970873419678087) -->
+ <skip />
+ <!-- no translation found for sms_isdn (8153785037515047845) -->
+ <skip />
+ <!-- no translation found for sms_main (8621625784504541679) -->
+ <skip />
+ <!-- no translation found for sms_other_fax (3888842199855843152) -->
+ <skip />
+ <!-- no translation found for sms_radio (3329166673433967820) -->
+ <skip />
+ <!-- no translation found for sms_telex (9034802430065267848) -->
+ <skip />
+ <!-- no translation found for sms_tty_tdd (6782284969132531532) -->
+ <skip />
+ <!-- no translation found for sms_work_mobile (2459939960512702560) -->
+ <skip />
+ <!-- no translation found for sms_work_pager (5566924423316960597) -->
+ <skip />
+ <!-- no translation found for sms_assistant (2773424339923116234) -->
+ <skip />
+ <!-- no translation found for sms_mms (4069352461380762677) -->
+ <skip />
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation_title (766292372438450432) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <!-- no translation found for clearFrequentsProgress_title (5157001637482794212) -->
+ <skip />
+ <!-- no translation found for status_available (5586870015822828392) -->
+ <skip />
+ <!-- no translation found for status_away (1838861100379804730) -->
+ <skip />
+ <!-- no translation found for status_busy (9147992455450257136) -->
+ <skip />
+ <string name="contactsList" msgid="8661624236494819731">"ಸಂಪರ್ಕಗಳು"</string>
+ <!-- no translation found for local_invisible_directory (6046691709127661065) -->
+ <skip />
+ <!-- no translation found for directory_search_label (1887759056597975053) -->
+ <skip />
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <!-- no translation found for local_search_label (2551177578246113614) -->
+ <skip />
+ <string name="search_results_searching" msgid="3984833028938569930">"ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
+ <!-- no translation found for foundTooManyContacts (5163335650920020220) -->
+ <skip />
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"ಯಾವುದೇ ಸಂಪರ್ಕಗಳಿಲ್ಲ"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ಕಂಡುಬಂದಿದೆ</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ಕಂಡುಬಂದಿದೆ</item>
+ </plurals>
+ <!-- no translation found for description_quick_contact_for (6737516415168327789) -->
+ <skip />
+ <!-- no translation found for missing_name (8745511583852904385) -->
+ <skip />
+ <!-- no translation found for favoritesFrequentContacted (6184232487472425690) -->
+ <skip />
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"ಸಂಪರ್ಕವನ್ನು ವೀಕ್ಷಿಸಿ"</string>
+ <!-- no translation found for list_filter_phones (735313795643493365) -->
+ <skip />
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <!-- no translation found for view_updates_from_group (1782685984905600034) -->
+ <skip />
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <!-- no translation found for nameLabelsGroup (2034640839640477827) -->
+ <skip />
+ <!-- no translation found for nicknameLabelsGroup (2891682101053358010) -->
+ <skip />
+ <!-- no translation found for full_name (6602579550613988977) -->
+ <skip />
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <!-- no translation found for name_prefix (59756378548779822) -->
+ <skip />
+ <!-- no translation found for name_middle (8467433655992690326) -->
+ <skip />
+ <!-- no translation found for name_suffix (3855278445375651441) -->
+ <skip />
+ <!-- no translation found for name_phonetic (4259595234312430484) -->
+ <skip />
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <!-- no translation found for name_phonetic_middle (8643721493320405200) -->
+ <skip />
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <!-- no translation found for phoneLabelsGroup (6468091477851199285) -->
+ <skip />
+ <!-- no translation found for emailLabelsGroup (8389931313045344406) -->
+ <skip />
+ <!-- no translation found for postalLabelsGroup (3487738141112589324) -->
+ <skip />
+ <!-- no translation found for imLabelsGroup (3898238486262614027) -->
+ <skip />
+ <!-- no translation found for organizationLabelsGroup (2478611760751832035) -->
+ <skip />
+ <!-- no translation found for relationLabelsGroup (1854373894284572781) -->
+ <skip />
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <!-- no translation found for sms (1756857139634224222) -->
+ <skip />
+ <!-- no translation found for postal_address (8765560217149624536) -->
+ <skip />
+ <!-- no translation found for ghostData_company (5414421120553765775) -->
+ <skip />
+ <!-- no translation found for ghostData_title (7496735200318496110) -->
+ <skip />
+ <!-- no translation found for label_notes (8337354953278341042) -->
+ <skip />
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <!-- no translation found for websiteLabelsGroup (4202998982804009261) -->
+ <skip />
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <!-- no translation found for email_home (8573740658148184279) -->
+ <skip />
+ <!-- no translation found for email_mobile (2042889209787989814) -->
+ <skip />
+ <!-- no translation found for email_work (2807430017302722689) -->
+ <skip />
+ <!-- no translation found for email_other (3454004077967657109) -->
+ <skip />
+ <!-- no translation found for email_custom (7548003991586214105) -->
+ <skip />
+ <!-- no translation found for email (5668400997660065897) -->
+ <skip />
+ <!-- no translation found for postal_street (8133143961580058972) -->
+ <skip />
+ <!-- no translation found for postal_pobox (4431938829180269821) -->
+ <skip />
+ <!-- no translation found for postal_neighborhood (1450783874558956739) -->
+ <skip />
+ <!-- no translation found for postal_city (6597491300084895548) -->
+ <skip />
+ <!-- no translation found for postal_region (6045263193478437672) -->
+ <skip />
+ <!-- no translation found for postal_postcode (572136414136673751) -->
+ <skip />
+ <!-- no translation found for postal_country (7638264508416368690) -->
+ <skip />
+ <!-- no translation found for map_home (1243547733423343982) -->
+ <skip />
+ <!-- no translation found for map_work (1360474076921878088) -->
+ <skip />
+ <!-- no translation found for map_other (3817820803587012641) -->
+ <skip />
+ <!-- no translation found for map_custom (6184363799976265281) -->
+ <skip />
+ <!-- no translation found for chat_aim (2588492205291249142) -->
+ <skip />
+ <!-- no translation found for chat_msn (8041633440091073484) -->
+ <skip />
+ <!-- no translation found for chat_yahoo (6629211142719943666) -->
+ <skip />
+ <!-- no translation found for chat_skype (1210045020427480566) -->
+ <skip />
+ <!-- no translation found for chat_qq (4294637812847719693) -->
+ <skip />
+ <!-- no translation found for chat_gtalk (981575737258117697) -->
+ <skip />
+ <!-- no translation found for chat_icq (8438405386153745775) -->
+ <skip />
+ <!-- no translation found for chat_jabber (7561444230307829609) -->
+ <skip />
+ <!-- no translation found for chat (9025361898797412245) -->
+ <skip />
+ <!-- no translation found for description_minus_button (6908099247930477551) -->
+ <skip />
+ <!-- no translation found for expand_collapse_name_fields_description (8682630859539604311) -->
+ <skip />
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <!-- no translation found for list_filter_all_accounts (8908683398914322369) -->
+ <skip />
+ <!-- no translation found for list_filter_all_starred (5031734941601931356) -->
+ <skip />
+ <!-- no translation found for list_filter_customize (4789963356004169321) -->
+ <skip />
+ <!-- no translation found for list_filter_single (5871400283515893087) -->
+ <skip />
+ <!-- no translation found for display_ungrouped (6885954210243119591) -->
+ <skip />
+ <!-- no translation found for display_all_contacts (2031647544742889505) -->
+ <skip />
+ <!-- no translation found for menu_sync_remove (3266725887008450161) -->
+ <skip />
+ <!-- no translation found for dialog_sync_add (8267045393119375803) -->
+ <skip />
+ <!-- no translation found for display_more_groups (2682547080423434170) -->
+ <skip />
+ <!-- no translation found for display_warn_remove_ungrouped (8872290721676651414) -->
+ <skip />
+ <!-- no translation found for savingDisplayGroups (2133152192716475939) -->
+ <skip />
+ <!-- no translation found for menu_done (796017761764190697) -->
+ <skip />
+ <!-- no translation found for menu_doNotSave (58593876893538465) -->
+ <skip />
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <!-- no translation found for import_from_sim (3859272228033941659) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <!-- no translation found for cancel_import_confirmation_message (3929951040347726757) -->
+ <skip />
+ <!-- no translation found for cancel_export_confirmation_message (1995462401949262638) -->
+ <skip />
+ <!-- no translation found for cancel_vcard_import_or_export_failed (6139900383366166706) -->
+ <skip />
+ <!-- no translation found for fail_reason_unknown (1714092345030570863) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_open_file (2067725459821997463) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_initialize_exporter (707260459259688510) -->
+ <skip />
+ <!-- no translation found for fail_reason_no_exportable_contact (8728506011371262065) -->
+ <skip />
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <!-- no translation found for fail_reason_error_occurred_during_export (3018855323913649063) -->
+ <skip />
+ <!-- no translation found for fail_reason_too_long_filename (3393764245254738333) -->
+ <skip />
+ <!-- no translation found for fail_reason_io_error (6748358842976073255) -->
+ <skip />
+ <!-- no translation found for fail_reason_low_memory_during_import (875222757734882898) -->
+ <skip />
+ <!-- no translation found for fail_reason_vcard_parse_error (888263542360355784) -->
+ <skip />
+ <!-- no translation found for fail_reason_not_supported (8219562769267148825) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_collect_vcard_meta_info (6427931733267328564) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title (4767045779458185251) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_canceled_title (2652222370493306887) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <!-- no translation found for composer_failed_to_get_database_infomation (1765944280846236723) -->
+ <skip />
+ <!-- no translation found for composer_has_no_exportable_contact (3296493229040294335) -->
+ <skip />
+ <!-- no translation found for composer_not_initialized (2321648986367005254) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_title (4892358112409576342) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_message (4938527850142003141) -->
+ <skip />
+ <!-- no translation found for importing_vcard_description (4245275224298571351) -->
+ <skip />
+ <!-- no translation found for reading_vcard_failed_title (4251647443358422855) -->
+ <skip />
+ <!-- no translation found for reading_vcard_canceled_title (1925216585981542019) -->
+ <skip />
+ <!-- no translation found for importing_vcard_finished_title (3341541727268747967) -->
+ <skip />
+ <!-- no translation found for importing_vcard_canceled_title (2147475978165599336) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message (2804911199145873396) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message_with_default_name (1022969530654129470) -->
+ <skip />
+ <!-- no translation found for vcard_import_request_rejected_message (2890471184508516011) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message (2210241345252081463) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <!-- no translation found for vcard_export_request_rejected_message (2844874826431327531) -->
+ <skip />
+ <!-- no translation found for vcard_unknown_filename (7171709890959915954) -->
+ <skip />
+ <!-- no translation found for caching_vcard_message (4926308675041506756) -->
+ <skip />
+ <!-- no translation found for vcard_import_failed (5223531255894842406) -->
+ <skip />
+ <!-- no translation found for nfc_vcard_file_name (2823095213265993609) -->
+ <skip />
+ <!-- no translation found for confirm_export_title (6834385377255286349) -->
+ <skip />
+ <!-- no translation found for caching_vcard_title (1226272312940516605) -->
+ <skip />
+ <!-- no translation found for progress_notifier_message (2311011466908220528) -->
+ <skip />
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
+ <!-- no translation found for share_visible_contacts (890150378880783797) -->
+ <skip />
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <!-- no translation found for dialog_import_export (4360648034889921624) -->
+ <skip />
+ <!-- no translation found for dialog_import (2431698729761448759) -->
+ <skip />
+ <!-- no translation found for share_error (948429331673358107) -->
+ <skip />
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <!-- no translation found for menu_search (9147752853603483719) -->
+ <skip />
+ <!-- no translation found for menu_contacts_filter (2165153460860262501) -->
+ <skip />
+ <!-- no translation found for activity_title_contacts_filter (8275542497615516969) -->
+ <skip />
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <!-- no translation found for contactsFavoritesLabel (8417039765586853670) -->
+ <skip />
+ <!-- no translation found for listTotalAllContactsZero (5513001821794568211) -->
+ <skip />
+ <!-- no translation found for menu_clear_frequents (7688250191932838833) -->
+ <skip />
+ <string name="menu_select_sim" msgid="3603578201960504010">"ಸಿಮ್ ಕಾರ್ಡ್ ಆಯ್ಕೆಮಾಡಿ"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <!-- no translation found for menu_import_export (26217871113229507) -->
+ <skip />
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"ನಿರ್ಬಂಧಿಸಲಾದ ಸಂಖ್ಯೆಗಳು"</string>
+ <!-- no translation found for contact_status_update_attribution (752179367353018597) -->
+ <skip />
+ <!-- no translation found for contact_status_update_attribution_with_date (7358045508107825068) -->
+ <skip />
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"ಹುಡುಕಾಟವನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ko/donottranslate_config.xml b/res/values-ko/donottranslate_config.xml
new file mode 100644
index 0000000..14cdd4d
--- /dev/null
+++ b/res/values-ko/donottranslate_config.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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>
+ <!-- If true, an option is shown in Display Options UI to choose a sort order -->
+ <bool name="config_sort_order_user_changeable">false</bool>
+
+ <!-- If true, the default sort order is primary (i.e. by given name) -->
+ <bool name="config_default_sort_order_primary">false</bool>
+
+ <!-- If true, an option is shown in Display Options UI to choose a name display order -->
+ <bool name="config_display_order_user_changeable">false</bool>
+
+ <!-- If true, the default sort order is primary (i.e. by given name) -->
+ <bool name="config_default_display_order_primary">false</bool>
+
+ <!-- If true, the order of name fields in the editor is primary (i.e. given name first) -->
+ <bool name="config_editor_field_order_primary">false</bool>
+</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 5c346de..6403259 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -210,7 +210,7 @@
<string name="contact_directory_description" msgid="683398073603909119">"디렉토리 <xliff:g id="TYPE">%1$s</xliff:g>"</string>
<string name="activity_title_settings" msgid="5464130076132770781">"설정"</string>
<string name="menu_settings" msgid="377929915873428211">"설정"</string>
- <string name="menu_help" msgid="1680178646764069976">"도움말 및 의견"</string>
+ <string name="menu_help" msgid="1680178646764069976">"고객센터"</string>
<string name="preference_displayOptions" msgid="1341720270148252393">"표시 옵션"</string>
<string name="organization_company_and_title" msgid="6718207751363732025">"<xliff:g id="COMPANY_0">%2$s</xliff:g>, <xliff:g id="COMPANY_1">%1$s</xliff:g>"</string>
<string name="non_phone_caption" msgid="1541655052330027380">"전화번호"</string>
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"기본으로 설정"</string>
<string name="clear_default" msgid="7193185801596678067">"기본 설정 지우기"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"텍스트 복사됨"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"변경사항을 취소하고 수정을 중단하시겠습니까?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"변경사항을 취소하시겠습니까?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"취소"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"계속 수정"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"취소"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"연락처 검색"</string>
<string name="title_edit_group" msgid="8602752287270586734">"연락처 삭제"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"정보"</string>
<string name="send_message" msgid="8938418965550543196">"메시지 보내기"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"개인 사본 작성 중..."</string>
- <string name="yesterday" msgid="6840858548955018569">"어제"</string>
<string name="tomorrow" msgid="6241969467795308581">"내일"</string>
<string name="today" msgid="8041090779381781781">"오늘"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"오늘 <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"메시지"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"목록 정리"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"중복된 항목을 정리하고 라벨로 연락처 그룹화"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"텍스트 복사됨"</string>
+ <string name="copy_text" msgid="3257145021583508761">"클립보드에 복사"</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="8563753966926932052">"전화걸기"</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="5745314124619636674">"팩스로 전화하기"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"문자 보내기"</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="3888842199855843152">"팩스로 문자 보내기"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"자주 연락하는 사람들 목록을 삭제하시겠습니까?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"자주 연락하는 사람들 목록을 삭제하는 중…"</string>
+ <string name="status_available" msgid="5586870015822828392">"대화 가능"</string>
+ <string name="status_away" msgid="1838861100379804730">"자리 비움"</string>
+ <string name="status_busy" msgid="9147992455450257136">"다른 용무 중"</string>
+ <string name="contactsList" msgid="8661624236494819731">"주소록"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"기타"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"디렉토리"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"모든 연락처"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"검색 중…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g>개 이상 찾았습니다."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"연락처 없음"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">연락처 <xliff:g id="COUNT">%d</xliff:g>개</item>
+ <item quantity="one">연락처 1개</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g>님의 빠른 주소록"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(이름 없음)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"자주 연락하는 사람들의 연락처"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"연락처 보기"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"전화번호가 포함된 모든 연락처"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"업데이트 보기"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"이름"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"닉네임"</string>
+ <string name="full_name" msgid="6602579550613988977">"이름"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"이름(소리나는 대로)"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"중간 이름(소리나는 대로)"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"전화"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"이메일"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"주소"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"메신저"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"조직"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"관계"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"문자 메시지"</string>
+ <string name="postal_address" msgid="8765560217149624536">"주소"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"회사"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"직함"</string>
+ <string name="label_notes" msgid="8337354953278341042">"메모"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"웹사이트"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"이메일"</string>
+ <string name="email_custom" msgid="7548003991586214105">"이메일(<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="email" msgid="5668400997660065897">"이메일"</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="map_home" msgid="1243547733423343982">"집 주소 보기"</string>
+ <string name="map_work" msgid="1360474076921878088">"직장 주소 보기"</string>
+ <string name="map_other" msgid="3817820803587012641">"주소 보기"</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="description_minus_button" msgid="6908099247930477551">"삭제"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"이름 입력란 펼치기/접기"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"모든 연락처"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"별표"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"맞춤설정"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"연락처"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"다른 모든 주소록"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"모든 주소록"</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_warn_remove_ungrouped" msgid="8872290721676651414">"\'<xliff:g id="GROUP">%s</xliff:g>\'을(를) 동기화에서 제거하면 그룹화되지 않은 연락처도 동기화에서 제거됩니다."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"표시 옵션 저장 중...."</string>
+ <string name="menu_done" msgid="796017761764190697">"완료"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"취소"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM 카드에서 가져오기"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> 가져오기를 취소하시겠습니까?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> 내보내기를 취소하시겠습니까?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard 가져오기/내보내기를 취소하지 못했습니다."</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"알 수 없는 오류입니다."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\'<xliff:g id="FILE_NAME">%s</xliff:g>\'을(를) 열 수 없습니다(이유: <xliff:g id="EXACT_REASON">%s</xliff:g>)."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"내보내기를 시작하지 못했습니다(이유: \'<xliff:g id="EXACT_REASON">%s</xliff:g>\')."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"내보낼 수 있는 연락처가 없습니다."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"내보내는 중에 오류가 발생했습니다(이유: \'<xliff:g id="EXACT_REASON">%s</xliff:g>\')."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"필수 파일 이름이 너무 깁니다(\'<xliff:g id="FILENAME">%s</xliff:g>\')."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O 오류"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"메모리가 부족합니다. 파일이 너무 크기 때문일 수 있습니다."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"예기치 못한 이유로 인해 vCard를 구문분석하지 못했습니다."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"지원되지 않는 형식입니다."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"지정한 vCard 파일에 대한 메타 정보를 수집하지 못했습니다."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"하나 이상의 파일을 가져오지 못했습니다(%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> 내보내기 완료됨"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> 내보내기 취소"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"연락처 데이터 내보내기"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"데이터베이스 정보를 가져오지 못했습니다."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"내보낼 수 있는 연락처가 없습니다. 휴대전화에 연락처가 있다면 일부 데이터 제공업체에서 연락처를 휴대전화에서 내보내지 못하도록 했기 때문일 수 있습니다."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard 작성기가 제대로 시작되지 않았습니다."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"내보내기 실패"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"주소록 데이터를 내보내지 못했습니다.\n(이유: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\')"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> 가져오는 중"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard 데이터를 읽지 못했습니다."</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard 데이터 읽기 취소"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"<xliff:g id="FILENAME">%s</xliff:g> vCard 가져오기 완료"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> 가져오기 취소"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g>을(를) 곧 가져옵니다."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"파일을 곧 가져옵니다."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard 가져오기 요청이 거부되었습니다. 나중에 다시 시도해 주세요."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g>을(를) 곧 내보냅니다."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard 내보내기 요청이 거부되었습니다. 나중에 다시 시도해 주세요."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"연락처"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard를 로컬 임시 저장공간에 캐시하는 중입니다. 곧 가져오기가 시작됩니다."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard를 가져오지 못했습니다."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC를 통해 받은 연락처"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"주소록을 내보내시겠습니까?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"캐시"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g> 가져오는 중: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"설정"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"표시되는 연락처 모두 공유"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"주소록 가져오기/내보내기"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"주소록 가져오기"</string>
+ <string name="share_error" msgid="948429331673358107">"연락처를 공유할 수 없습니다."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"검색"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"표시할 연락처"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"표시할 연락처"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"즐겨찾기"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"연락처가 없습니다."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"자주 연락하는 사람들 목록 삭제"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM 카드 선택"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"가져오기/내보내기"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"차단된 번호"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"출처: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g>(출처: <xliff:g id="SOURCE">%2$s</xliff:g>)"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"검색창 지우기"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
index 61c6594..7a287e1 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky-rKG/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Негизги кылуу"</string>
<string name="clear_default" msgid="7193185801596678067">"Негизгини тазалоо"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"SMS көчүрүлдү"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Өзгөртүүлөр жарактан чыгарылып, түзөтүү жабылсынбы?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Өзгөрүүлөр жарактан чыгарылсынбы?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Жарактан чыгаруу"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Түзөтө берүү"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Баш тартуу"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Байланыштардан издеп көрүңүз"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Байланыштарды алып салуу"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Жөнүндө"</string>
<string name="send_message" msgid="8938418965550543196">"Билдирүү жөнөтүү"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Жеке көчүрмөсүн түзүү…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Кечээ"</string>
<string name="tomorrow" msgid="6241969467795308581">"Эртең"</string>
<string name="today" msgid="8041090779381781781">"Бүгүн"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Бүгүн саат <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,505 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Билдирүүлөр"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Тизмеңизди ирээттеңиз"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Байланыштарды топтор боюнча белгилеп, окшошторун өчүрүп салыңыз."</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"SMS көчүрүлдү"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Алмашуу буферине көчүрүү"</string>
+ <!-- no translation found for call_custom (7756571794763171802) -->
+ <skip />
+ <!-- no translation found for call_home (1990519474420545392) -->
+ <skip />
+ <!-- no translation found for call_mobile (7502236805487609178) -->
+ <skip />
+ <!-- no translation found for call_work (5328785911463744028) -->
+ <skip />
+ <!-- no translation found for call_fax_work (7467763592359059243) -->
+ <skip />
+ <!-- no translation found for call_fax_home (8342175628887571876) -->
+ <skip />
+ <!-- no translation found for call_pager (9003902812293983281) -->
+ <skip />
+ <!-- no translation found for call_other (8563753966926932052) -->
+ <skip />
+ <!-- no translation found for call_callback (1910165691349426858) -->
+ <skip />
+ <!-- no translation found for call_car (3280537320306436445) -->
+ <skip />
+ <!-- no translation found for call_company_main (6105120947138711257) -->
+ <skip />
+ <!-- no translation found for call_isdn (1541590690193403411) -->
+ <skip />
+ <!-- no translation found for call_main (6082900571803441339) -->
+ <skip />
+ <!-- no translation found for call_other_fax (5745314124619636674) -->
+ <skip />
+ <!-- no translation found for call_radio (8296755876398357063) -->
+ <skip />
+ <!-- no translation found for call_telex (2223170774548648114) -->
+ <skip />
+ <!-- no translation found for call_tty_tdd (8951266948204379604) -->
+ <skip />
+ <!-- no translation found for call_work_mobile (8707874281430105394) -->
+ <skip />
+ <!-- no translation found for call_work_pager (3419348514157949008) -->
+ <skip />
+ <!-- no translation found for call_assistant (2141641383068514308) -->
+ <skip />
+ <!-- no translation found for call_mms (6274041545876221437) -->
+ <skip />
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <!-- no translation found for sms_custom (5932736853732191825) -->
+ <skip />
+ <!-- no translation found for sms_home (7524332261493162995) -->
+ <skip />
+ <!-- no translation found for sms_mobile (5200107250451030769) -->
+ <skip />
+ <!-- no translation found for sms_work (2269624156655267740) -->
+ <skip />
+ <!-- no translation found for sms_fax_work (8028189067816907075) -->
+ <skip />
+ <!-- no translation found for sms_fax_home (9204042076306809634) -->
+ <skip />
+ <!-- no translation found for sms_pager (7730404569637015192) -->
+ <skip />
+ <!-- no translation found for sms_other (806127844607642331) -->
+ <skip />
+ <!-- no translation found for sms_callback (5004824430094288752) -->
+ <skip />
+ <!-- no translation found for sms_car (7444227058437359641) -->
+ <skip />
+ <!-- no translation found for sms_company_main (118970873419678087) -->
+ <skip />
+ <!-- no translation found for sms_isdn (8153785037515047845) -->
+ <skip />
+ <!-- no translation found for sms_main (8621625784504541679) -->
+ <skip />
+ <!-- no translation found for sms_other_fax (3888842199855843152) -->
+ <skip />
+ <!-- no translation found for sms_radio (3329166673433967820) -->
+ <skip />
+ <!-- no translation found for sms_telex (9034802430065267848) -->
+ <skip />
+ <!-- no translation found for sms_tty_tdd (6782284969132531532) -->
+ <skip />
+ <!-- no translation found for sms_work_mobile (2459939960512702560) -->
+ <skip />
+ <!-- no translation found for sms_work_pager (5566924423316960597) -->
+ <skip />
+ <!-- no translation found for sms_assistant (2773424339923116234) -->
+ <skip />
+ <!-- no translation found for sms_mms (4069352461380762677) -->
+ <skip />
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation_title (766292372438450432) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <!-- no translation found for clearFrequentsProgress_title (5157001637482794212) -->
+ <skip />
+ <!-- no translation found for status_available (5586870015822828392) -->
+ <skip />
+ <!-- no translation found for status_away (1838861100379804730) -->
+ <skip />
+ <!-- no translation found for status_busy (9147992455450257136) -->
+ <skip />
+ <string name="contactsList" msgid="8661624236494819731">"Байланыштар"</string>
+ <!-- no translation found for local_invisible_directory (6046691709127661065) -->
+ <skip />
+ <!-- no translation found for directory_search_label (1887759056597975053) -->
+ <skip />
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <!-- no translation found for local_search_label (2551177578246113614) -->
+ <skip />
+ <string name="search_results_searching" msgid="3984833028938569930">"Изделүүдө…"</string>
+ <!-- no translation found for foundTooManyContacts (5163335650920020220) -->
+ <skip />
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Байланыштар жок"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> табылды</item>
+ <item quantity="one">1 табылды</item>
+ </plurals>
+ <!-- no translation found for description_quick_contact_for (6737516415168327789) -->
+ <skip />
+ <!-- no translation found for missing_name (8745511583852904385) -->
+ <skip />
+ <!-- no translation found for favoritesFrequentContacted (6184232487472425690) -->
+ <skip />
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Байланышты карап көрүү"</string>
+ <!-- no translation found for list_filter_phones (735313795643493365) -->
+ <skip />
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <!-- no translation found for view_updates_from_group (1782685984905600034) -->
+ <skip />
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <!-- no translation found for nameLabelsGroup (2034640839640477827) -->
+ <skip />
+ <!-- no translation found for nicknameLabelsGroup (2891682101053358010) -->
+ <skip />
+ <!-- no translation found for full_name (6602579550613988977) -->
+ <skip />
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <!-- no translation found for name_prefix (59756378548779822) -->
+ <skip />
+ <!-- no translation found for name_middle (8467433655992690326) -->
+ <skip />
+ <!-- no translation found for name_suffix (3855278445375651441) -->
+ <skip />
+ <!-- no translation found for name_phonetic (4259595234312430484) -->
+ <skip />
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <!-- no translation found for name_phonetic_middle (8643721493320405200) -->
+ <skip />
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <!-- no translation found for phoneLabelsGroup (6468091477851199285) -->
+ <skip />
+ <!-- no translation found for emailLabelsGroup (8389931313045344406) -->
+ <skip />
+ <!-- no translation found for postalLabelsGroup (3487738141112589324) -->
+ <skip />
+ <!-- no translation found for imLabelsGroup (3898238486262614027) -->
+ <skip />
+ <!-- no translation found for organizationLabelsGroup (2478611760751832035) -->
+ <skip />
+ <!-- no translation found for relationLabelsGroup (1854373894284572781) -->
+ <skip />
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <!-- no translation found for sms (1756857139634224222) -->
+ <skip />
+ <!-- no translation found for postal_address (8765560217149624536) -->
+ <skip />
+ <!-- no translation found for ghostData_company (5414421120553765775) -->
+ <skip />
+ <!-- no translation found for ghostData_title (7496735200318496110) -->
+ <skip />
+ <!-- no translation found for label_notes (8337354953278341042) -->
+ <skip />
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <!-- no translation found for websiteLabelsGroup (4202998982804009261) -->
+ <skip />
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <!-- no translation found for email_home (8573740658148184279) -->
+ <skip />
+ <!-- no translation found for email_mobile (2042889209787989814) -->
+ <skip />
+ <!-- no translation found for email_work (2807430017302722689) -->
+ <skip />
+ <!-- no translation found for email_other (3454004077967657109) -->
+ <skip />
+ <!-- no translation found for email_custom (7548003991586214105) -->
+ <skip />
+ <!-- no translation found for email (5668400997660065897) -->
+ <skip />
+ <!-- no translation found for postal_street (8133143961580058972) -->
+ <skip />
+ <!-- no translation found for postal_pobox (4431938829180269821) -->
+ <skip />
+ <!-- no translation found for postal_neighborhood (1450783874558956739) -->
+ <skip />
+ <!-- no translation found for postal_city (6597491300084895548) -->
+ <skip />
+ <!-- no translation found for postal_region (6045263193478437672) -->
+ <skip />
+ <!-- no translation found for postal_postcode (572136414136673751) -->
+ <skip />
+ <!-- no translation found for postal_country (7638264508416368690) -->
+ <skip />
+ <!-- no translation found for map_home (1243547733423343982) -->
+ <skip />
+ <!-- no translation found for map_work (1360474076921878088) -->
+ <skip />
+ <!-- no translation found for map_other (3817820803587012641) -->
+ <skip />
+ <!-- no translation found for map_custom (6184363799976265281) -->
+ <skip />
+ <!-- no translation found for chat_aim (2588492205291249142) -->
+ <skip />
+ <!-- no translation found for chat_msn (8041633440091073484) -->
+ <skip />
+ <!-- no translation found for chat_yahoo (6629211142719943666) -->
+ <skip />
+ <!-- no translation found for chat_skype (1210045020427480566) -->
+ <skip />
+ <!-- no translation found for chat_qq (4294637812847719693) -->
+ <skip />
+ <!-- no translation found for chat_gtalk (981575737258117697) -->
+ <skip />
+ <!-- no translation found for chat_icq (8438405386153745775) -->
+ <skip />
+ <!-- no translation found for chat_jabber (7561444230307829609) -->
+ <skip />
+ <!-- no translation found for chat (9025361898797412245) -->
+ <skip />
+ <!-- no translation found for description_minus_button (6908099247930477551) -->
+ <skip />
+ <!-- no translation found for expand_collapse_name_fields_description (8682630859539604311) -->
+ <skip />
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <!-- no translation found for list_filter_all_accounts (8908683398914322369) -->
+ <skip />
+ <!-- no translation found for list_filter_all_starred (5031734941601931356) -->
+ <skip />
+ <!-- no translation found for list_filter_customize (4789963356004169321) -->
+ <skip />
+ <!-- no translation found for list_filter_single (5871400283515893087) -->
+ <skip />
+ <!-- no translation found for display_ungrouped (6885954210243119591) -->
+ <skip />
+ <!-- no translation found for display_all_contacts (2031647544742889505) -->
+ <skip />
+ <!-- no translation found for menu_sync_remove (3266725887008450161) -->
+ <skip />
+ <!-- no translation found for dialog_sync_add (8267045393119375803) -->
+ <skip />
+ <!-- no translation found for display_more_groups (2682547080423434170) -->
+ <skip />
+ <!-- no translation found for display_warn_remove_ungrouped (8872290721676651414) -->
+ <skip />
+ <!-- no translation found for savingDisplayGroups (2133152192716475939) -->
+ <skip />
+ <!-- no translation found for menu_done (796017761764190697) -->
+ <skip />
+ <!-- no translation found for menu_doNotSave (58593876893538465) -->
+ <skip />
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <!-- no translation found for import_from_sim (3859272228033941659) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <!-- no translation found for cancel_import_confirmation_message (3929951040347726757) -->
+ <skip />
+ <!-- no translation found for cancel_export_confirmation_message (1995462401949262638) -->
+ <skip />
+ <!-- no translation found for cancel_vcard_import_or_export_failed (6139900383366166706) -->
+ <skip />
+ <!-- no translation found for fail_reason_unknown (1714092345030570863) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_open_file (2067725459821997463) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_initialize_exporter (707260459259688510) -->
+ <skip />
+ <!-- no translation found for fail_reason_no_exportable_contact (8728506011371262065) -->
+ <skip />
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <!-- no translation found for fail_reason_error_occurred_during_export (3018855323913649063) -->
+ <skip />
+ <!-- no translation found for fail_reason_too_long_filename (3393764245254738333) -->
+ <skip />
+ <!-- no translation found for fail_reason_io_error (6748358842976073255) -->
+ <skip />
+ <!-- no translation found for fail_reason_low_memory_during_import (875222757734882898) -->
+ <skip />
+ <!-- no translation found for fail_reason_vcard_parse_error (888263542360355784) -->
+ <skip />
+ <!-- no translation found for fail_reason_not_supported (8219562769267148825) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_collect_vcard_meta_info (6427931733267328564) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title (4767045779458185251) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_canceled_title (2652222370493306887) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <!-- no translation found for composer_failed_to_get_database_infomation (1765944280846236723) -->
+ <skip />
+ <!-- no translation found for composer_has_no_exportable_contact (3296493229040294335) -->
+ <skip />
+ <!-- no translation found for composer_not_initialized (2321648986367005254) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_title (4892358112409576342) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_message (4938527850142003141) -->
+ <skip />
+ <!-- no translation found for importing_vcard_description (4245275224298571351) -->
+ <skip />
+ <!-- no translation found for reading_vcard_failed_title (4251647443358422855) -->
+ <skip />
+ <!-- no translation found for reading_vcard_canceled_title (1925216585981542019) -->
+ <skip />
+ <!-- no translation found for importing_vcard_finished_title (3341541727268747967) -->
+ <skip />
+ <!-- no translation found for importing_vcard_canceled_title (2147475978165599336) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message (2804911199145873396) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message_with_default_name (1022969530654129470) -->
+ <skip />
+ <!-- no translation found for vcard_import_request_rejected_message (2890471184508516011) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message (2210241345252081463) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <!-- no translation found for vcard_export_request_rejected_message (2844874826431327531) -->
+ <skip />
+ <!-- no translation found for vcard_unknown_filename (7171709890959915954) -->
+ <skip />
+ <!-- no translation found for caching_vcard_message (4926308675041506756) -->
+ <skip />
+ <!-- no translation found for vcard_import_failed (5223531255894842406) -->
+ <skip />
+ <!-- no translation found for nfc_vcard_file_name (2823095213265993609) -->
+ <skip />
+ <!-- no translation found for confirm_export_title (6834385377255286349) -->
+ <skip />
+ <!-- no translation found for caching_vcard_title (1226272312940516605) -->
+ <skip />
+ <!-- no translation found for progress_notifier_message (2311011466908220528) -->
+ <skip />
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Жөндөөлөр"</string>
+ <!-- no translation found for share_visible_contacts (890150378880783797) -->
+ <skip />
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <!-- no translation found for dialog_import_export (4360648034889921624) -->
+ <skip />
+ <!-- no translation found for dialog_import (2431698729761448759) -->
+ <skip />
+ <!-- no translation found for share_error (948429331673358107) -->
+ <skip />
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <!-- no translation found for menu_search (9147752853603483719) -->
+ <skip />
+ <!-- no translation found for menu_contacts_filter (2165153460860262501) -->
+ <skip />
+ <!-- no translation found for activity_title_contacts_filter (8275542497615516969) -->
+ <skip />
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <!-- no translation found for contactsFavoritesLabel (8417039765586853670) -->
+ <skip />
+ <!-- no translation found for listTotalAllContactsZero (5513001821794568211) -->
+ <skip />
+ <!-- no translation found for menu_clear_frequents (7688250191932838833) -->
+ <skip />
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM карта тандаңыз"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <!-- no translation found for menu_import_export (26217871113229507) -->
+ <skip />
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Бөгөттөлгөн номерлер"</string>
+ <!-- no translation found for contact_status_update_attribution (752179367353018597) -->
+ <skip />
+ <!-- no translation found for contact_status_update_attribution_with_date (7358045508107825068) -->
+ <skip />
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Издөөнү тазалоо"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-land/integers.xml b/res/values-land/integers.xml
index 8bc7b04..4b26d4c 100644
--- a/res/values-land/integers.xml
+++ b/res/values-land/integers.xml
@@ -22,4 +22,9 @@
<!-- Top margin ratio for the image for empty account view -->
<integer name="empty_account_view_image_margin_divisor">6</integer>
+
+ <integer name="contact_tile_column_count_in_favorites">3</integer>
+
+ <!-- The number of characters in the snippet before we need to tokenize and ellipse. -->
+ <integer name="snippet_length_before_tokenize">60</integer>
</resources>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
index 12bb70b..bfeac61 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo-rLA/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"ຕັ້ງຄ່າເລີ່ມຕົ້ນ"</string>
<string name="clear_default" msgid="7193185801596678067">"ລຶບຄ່າເລີ່ມຕົ້ນ"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"ສຳເນົາຂໍ້ຄວາມແລ້ວ"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"ຍົກເລີກການປ່ຽນແປງຂອງທ່ານ ແລະ ອອກຈາກການແກ້ໄຂບໍ?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"ຍົກເລີກການແກ້ໄຂບໍ່?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"ຍົກເລີກ"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"ສືບຕໍ່ແກ້ໄຂ"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"ຍົກເລີກ"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"ຊອກຫາລາຍຊື່ຜູ້ຕິດຕໍ່"</string>
<string name="title_edit_group" msgid="8602752287270586734">"ລຶບລາຍຊື່ຜູ້ຕິດຕໍ່"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"ກ່ຽວກັບ"</string>
<string name="send_message" msgid="8938418965550543196">"ສົ່ງຂໍ້ຄວາມ"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"ກຳລັງສ້າງສຳເນົາສ່ວນໂຕ..."</string>
- <string name="yesterday" msgid="6840858548955018569">"ມື້ວານນີ້"</string>
<string name="tomorrow" msgid="6241969467795308581">"ມື້ອື່ນ"</string>
<string name="today" msgid="8041090779381781781">"ມື້ນີ້"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"ມື້ນີ້ໃນເວລາ <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"ຂໍ້ຄວາມ"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"ຈັດລະບຽບລາຍຊື່ຂອງທ່ານ"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"ລຶບລ້າງລາຍຊື່ຜູ້ຕິດຕໍ່ທີ່ຊ້ຳກັນ ແລະ ຈັດກຸ່ມຕາມປ້າຍກຳກັບ"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"ສຳເນົາຂໍ້ຄວາມແລ້ວ"</string>
+ <string name="copy_text" msgid="3257145021583508761">"ສຳເນົາໃສ່ຄລິບບອດ"</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">"ໂທຫາເບີ pager"</string>
+ <string name="call_other" msgid="8563753966926932052">"ໂທ"</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="5745314124619636674">"ໂທຫາເບີແຟັກ"</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">"ໂທຫາ pager ບ່ອນເຮັດວຽກ"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"ໂທຫາ <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"ໂທຫາເບີ MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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">"ສົ່ງຂໍ້ຄວາມຫາ pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"ສົ່ງຂໍ້ຄວາມ"</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="3888842199855843152">"ສົ່ງຂໍ້ຄວາມຫາແຟັກ"</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">"ສົ່ງຂໍ້ຄວາມຫາເບີ pager ບ່ອນເຮັດວຽກ"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"ສົ່ງຂໍ້ຄວາມຫາ <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"ສົ່ງຂໍ້ຄວາມ MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"ລຶບລາຍຊື່ທີ່ຕິດຕໍ່ຫາເລື້ອຍໆ?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"ກຳລັງລຶບລາຍຊື່ທີ່ຕິດຕໍ່ຫາເລື້ອຍໆ"</string>
+ <string name="status_available" msgid="5586870015822828392">"ສາມາດໃຊ້ໄດ້"</string>
+ <string name="status_away" msgid="1838861100379804730">"ບໍ່ຢູ່"</string>
+ <string name="status_busy" msgid="9147992455450257136">"ບໍ່ຫວ່າງ"</string>
+ <string name="contactsList" msgid="8661624236494819731">"ລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"ອື່ນໆ"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"ໄດເຣັກທໍຣີ"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"ລາຍຊື່ຜູ່ຕິດຕໍ່ທັງໝົດ"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"ກຳລັງຊອກຫາ..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"ພົບຫຼາຍກວ່າ <xliff:g id="COUNT">%d</xliff:g> ລາຍການ."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"ບໍ່ມີລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ພົບແລ້ວ</item>
+ <item quantity="one">1 ພົບແລ້ວ</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"ຂໍ້ມູນຕິດຕໍ່ດ່ວນສຳລັບ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(ບໍ່ມີຊື່)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"ລາຍຊື່ທີ່ຕິດຕໍ່ເລື້ອຍໆ"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"ເບິ່ງລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"ລາຍຊື່ຜູ່ຕິດຕໍ່ທັງໝົດທີ່ມີເບີໂທລະສັບ"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"ເບິ່ງອັບເດດ"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"ຊື່"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"ຊື່ຫຼິ້ນ"</string>
+ <string name="full_name" msgid="6602579550613988977">"ຊື່"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"ການອ່ານອອກສຽງຊື່"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"ການອອກສຽງຊື່ກາງ"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Phone"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"ອີເມວ"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"ທີ່ຢູ່"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"ອົງກອນ"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"ຄວາມສຳພັນ"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"ຂໍ້ຄວາມ"</string>
+ <string name="postal_address" msgid="8765560217149624536">"ທີ່ຢູ່"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"ບໍລິສັດ"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"ຊື່"</string>
+ <string name="label_notes" msgid="8337354953278341042">"ໝາຍເຫດ"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"ເວັບໄຊ"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"ອີເມວ"</string>
+ <string name="email_custom" msgid="7548003991586214105">"ສົ່ງອີເມວຫາ <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"ອີເມວ"</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">"ລະຫັດ ZIP"</string>
+ <string name="postal_country" msgid="7638264508416368690">"ປະເທດ"</string>
+ <string name="map_home" msgid="1243547733423343982">"ເບິ່ງທີ່ຢູ່ເຮືອນ"</string>
+ <string name="map_work" msgid="1360474076921878088">"ເບິ່ງທີ່ຢູ່ບ່ອນເຮັດວຽກ"</string>
+ <string name="map_other" msgid="3817820803587012641">"ເບິ່ງທີ່ຢູ່"</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="description_minus_button" msgid="6908099247930477551">"ລຶບ"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"ຂະຫຍາຍ ຫຼືຫຍໍ້ຊ່ອງຂໍ້ມູນຊື່"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"ລາຍຊື່ຜູ່ຕິດຕໍ່ທັງໝົດ"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"ຕິດດາວແລ້ວ"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"ປັບແຕ່ງ"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"ລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"ລາຍຊື່ຜູ່ຕິດຕໍ່ອື່ນໆທັງໝົດ"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"ລາຍຊື່ຜູ່ຕິດຕໍ່ທັງໝົດ"</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_warn_remove_ungrouped" msgid="8872290721676651414">"ການລຶບກຸ່ມ \"<xliff:g id="GROUP">%s</xliff:g>\" ອອກຈາກການຊິ້ງຂໍ້ມູນ ຈະເປັນການລຶບລາຍຊື່ຜູ່ຕິດຕໍ່ທີ່ບໍ່ໄດ້ຢູ່ໃນກຸ່ມ ອອກຈາກການຊິ້ງຂໍ້ມູນນຳ."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"ກຳລັງບັນທຶກໂຕເລືອກການສະແດງຜົນ..."</string>
+ <string name="menu_done" msgid="796017761764190697">"ແລ້ວໆ"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"ຍົກເລີກ"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"ນຳເຂົ້າຈາກ SIM card"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"ຍົກເລີກການນຳເຂົ້າ <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"ຍົກເລີກການສົ່ງອອກ <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"ບໍ່ສາມາດຍົກເລີກການ ນຳເຂົ້າ/ສົ່ງອອກ vCard ໄດ້"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"ຄວາມຜິດພາດທີ່ບໍ່ຮູ້ເຫດຜົນ."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"ບໍ່ສາມາດເປີດ \"<xliff:g id="FILE_NAME">%s</xliff:g>\" ໄດ້: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"ບໍ່ສາມາດເລີ່ມໂປຣແກຣມສົ່ງອອກໄດ້: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"ບໍ່ມີລາຍຊື່ຜູ່ຕິດຕໍ່ທີ່ສາມາດສົ່ງອອກໄດ້."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"ເກີດຄວາມຜິດພາດໃນລະຫວ່າງການສົ່ງອອກ: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"ຊື່ທີ່ຕ້ອງການນັ້ນຍາວເກີນໄປ (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O ຜິດພາດ"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"ໜ່ວຍຄວາມຈຳບໍ່ພໍ. ເປັນໄປໄດ້ວ່າໄຟລ໌ອາດໃຫຍ່ເກີນໄປ."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"ບໍ່ສາມາດວິເຄາະຂໍ້ມູນ vCard ເນື່ອງຈາກເຫດຜົນທີ່ບໍ່ຄາດຄິດ."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"ບໍ່ຮອງຮັບຮູບແບບທີ່ເລືອກ."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"ບໍ່ສາມາດເກັບກຳຂໍ້ມູນ meta ຂອງໄຟລ໌ vCard ທີ່ລະບຸໄດ້."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"ມີນຶ່ງໄຟລ໌ ຫຼືຫຼາຍກວ່ານັ້ນບໍ່ສາມາດຖືກນຳເຂົ້າໄດ້ (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"ການສົ່ງອອກ <xliff:g id="FILENAME">%s</xliff:g> ສິ້ນສຸດແລ້ວ."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"ການສົ່ງອອກ <xliff:g id="FILENAME">%s</xliff:g> ຖືກຍົກເລີກແລ້ວ."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"ກຳລັງສົ່ງອອກຂໍ້ມູນລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"ບໍ່ສາມາດດຶງຂໍ້ມູນຂອງຖານຂໍ້ມູນ."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"ບໍ່ມີລາຍຊື່ຜູ່ຕິດຕໍ່ທີ່ສາມາດສົ່ງອອກໄດ້. ຫາກທ່ານມີລາຍຊື່ຜູ່ຕິດຕໍ່ໃນໂທລະສັບຂອງທ່ານ ແຕ່ບໍ່ສາມາດສົ່ງອອກໄດ້ ກໍອາດເປັນເພາະບາງຜູ່ໃຫ້ບໍລິການຂໍ້ມູນບໍ່ອະນຸຍາດ ໃຫ້ສົ່ງລາຍຊື່ຜູ່ຕິດຕໍ່ອອກຈາກໂທລະສັບໄດ້."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"ໂປຣແກຣມຂຽນ vCard ຖືກເລີ່ມຢ່າງບໍ່ຖືກຕ້ອງ."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"ບໍ່ສາມາດສົ່ງອອກໄດ້"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"ບໍ່ໄດ້ສົ່ງຂໍ້ມູນລາຍຊື່ຜູ່ຕິດຕໍ່ອອກເທື່ອ.\nເຫດຜົນ: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"ກຳລັງນຳເຂົ້າ <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"ບໍ່ສາມາດອ່ານຂໍ້ມູນ vCard ໄດ້"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"ການອ່ານຂໍ້ມູນ vCard ຖືກຍົກເລີກແລ້ວ"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"ສິ້ນສຸດການນຳເຂົ້າໄຟລ໌ vCard <xliff:g id="FILENAME">%s</xliff:g> ແລ້ວ"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"ການນຳເຂົ້າ <xliff:g id="FILENAME">%s</xliff:g> ຖືກຍົກເລີກແລ້ວ"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> ຈະຖືກນຳເຂົ້າໄວໆນີ້."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"ໄຟລ໌ຈະຖືກນຳເຂົ້າໃນໄວໆນີ້."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"ຄຳຂໍການນຳເຂົ້າ vCard ຖືກປະຕິເສດ. ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> ຈະຖືກສົ່ງອອກໄວໆນີ້."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"ຄຳຂໍການສົ່ງ vCard ອອກ ຖືກປະຕິເສດ. ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"ລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"ກຳລັງເກັບຂໍ້ມູນ vCard ໃສ່ບ່ອນຈັດເກັບຂໍ້ມູນຊົ່ວຄາວໃນອຸປະກອນ. ການນຳເຂົ້າຈະເລີ່ມຂຶ້ນໃນໄວໆນີ້."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"ບໍ່ສາມາດນຳເຂົ້າ vCard ໄດ້."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"ລາຍຊື່ຜູ່ຕິດຕໍ່ທີ່ໄດ້ຮັບຜ່ານ NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"ສົ່ງອອກລາຍຊື່ຜູ່ຕິດຕໍ່?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"ກຳລັງເກັບຂໍ້ມູນ"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"ກຳລັງນຳເຂົ້າ <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"ການຕັ້ງຄ່າ"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"ແບ່ງປັນລາຍຊື່ຜູ່ຕິດຕໍ່ທີ່ເບິ່ງເຫັນໄດ້"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"ນຳເຂົ້າ/ສົ່ງອອກ ລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"ນຳເຂົ້າລາຍຊື່ຜູ່ຕິດຕໍ່"</string>
+ <string name="share_error" msgid="948429331673358107">"ບໍ່ສາມາດແບ່ງປັນລາຍຊື່ຜູ່ຕິດຕໍ່ນີ້ໄດ້"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"ຊອກຫາ"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"ລາຍຊື່ຜູ່ຕິດຕໍ່ເພື່ອສະແດງ"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"ລາຍຊື່ຜູ່ຕິດຕໍ່ທີ່ຈະສະແດງ"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"ລາຍການທີ່ມັກ"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"ບໍ່ມີລາຍຊື່ຜູ່ຕິດຕໍ່."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"ລຶບລາຍຊື່ທີ່ຕິດຕໍ່ເລື້ອຍໆ"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"ເລືອກ SIM ກາດ"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"ນຳເຂົ້າ/ສົ່ງອອກ"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"ເບີໂທທີ່ບລັອກໄວ້"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"ຜ່ານ <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> ຜ່ານ <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"ລຶບການຊອກຫາ"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 1e51eeb..a532893 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -246,9 +246,9 @@
<string name="set_default" msgid="4417505153468300351">"Nustatyti numatytuosius nustatymus"</string>
<string name="clear_default" msgid="7193185801596678067">"Išvalyti numatytuosius nustatymus"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Tekstas nukopijuotas"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Atmesti pakeitimus ir baigti redagavimą?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Atmesti pakeitimus?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Atmesti"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Toliau redaguoti"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Atšaukti"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Ieškokite kontaktų"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Pašalinti kontaktus"</string>
@@ -273,7 +273,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Apie"</string>
<string name="send_message" msgid="8938418965550543196">"Siųsti pranešimą"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Kuriama asmeninė kopija..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Vakar"</string>
<string name="tomorrow" msgid="6241969467795308581">"Rytoj"</string>
<string name="today" msgid="8041090779381781781">"Šiandien"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Šiandien, <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -364,4 +363,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Pranešimai"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Tvarkykite sąrašą"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Išvalykite tikslias kopijas ir pagal etiketes grupuokite kontaktus"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Tekstas nukopijuotas"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopijuoti į iškarpinę"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Skambinti <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Skambinti į namų telefoną"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Skambinti į mobilųjį telefoną"</string>
+ <string name="call_work" msgid="5328785911463744028">"Skambinti į darbo telefoną"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Skambinti į darbo faksą"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Skambinti į namų faksą"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Skambinti į pranešimų gaviklį"</string>
+ <string name="call_other" msgid="8563753966926932052">"Skambinti"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Skambinti atgalinio skambinimo būdu"</string>
+ <string name="call_car" msgid="3280537320306436445">"Skambinti automobilio telefono numeriu"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Skambinti į pagrindinį įmonės telefoną"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Skambinti ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Skambinti į pagrindinį telefoną"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Skambinti fakso numeriu"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Skambinti radijo telefono numeriu"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Skambinti telekso numeriu"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Skambinti TTY / TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Skambinti darbo mobiliuoju telefonu"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Skambinti į darbo pranešimų gaviklį"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Skambinti <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Skambinti MMS telefono numeriu"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Siųsti teksto pranešimą <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Siųsti teksto pranešimą į namų telefoną"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Siųsti teksto pranešimą į mobilųjį telefoną"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Siųsti pranešimą į darbo telefoną"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Siųsti pranešimą į darbo faksą"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Siųsti pranešimą į namų faksą"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Siųsti pranešimą į pranešimų gaviklį"</string>
+ <string name="sms_other" msgid="806127844607642331">"Tekstas"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Siųsti pranešimą atgalinio skambinimo numeriu"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Siųsti teksto pranešimą į automobilio telefoną"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Siųsti pranešimą pagrindiniu įmonės telefono numeriu"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Siųsti pranešimą ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Siųsti SMS į pagrindinį telefoną"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Siųsti teksto pranešimą į faksą"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Siųsti teksto pranešimą radijo telefono numeriu"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Siųsti pranešimą telekso numeriu"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Siųsti pranešimą TTY / TDD numeriu"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Siųsti pranešimą į darbo mobilųjį telefoną"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Siųsti pranešimą į darbo teksto pranešimų gaviklį"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Siųsti teksto pranešimą <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Siųsti MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Išvalyti dažniaus. naud. kontaktus?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Valomi dažniaus. naud. kontaktai…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Pasiekiamas"</string>
+ <string name="status_away" msgid="1838861100379804730">"Pasišalinęs"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Užsiėmęs"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Adresinė"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Kita"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Katalogas"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Visi kontaktai"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Ieškoma…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Rasta daugiau nei <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Kontaktų nėra"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one">Rastas <xliff:g id="COUNT">%d</xliff:g> kontaktas</item>
+ <item quantity="few">Rasti <xliff:g id="COUNT">%d</xliff:g> kontaktai</item>
+ <item quantity="many">Rasta <xliff:g id="COUNT">%d</xliff:g> kontakto</item>
+ <item quantity="other">Rasta <xliff:g id="COUNT">%d</xliff:g> kontaktų</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Spartusis <xliff:g id="NAME">%1$s</xliff:g> kontaktas"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Nėra pavadinimo)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Dažnai susisiekiama"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Peržiūrėti kontaktą"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Visi kontaktai su telefonų numeriais"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Žiūrėti naujinius"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Pavadinimas"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Slapyvardis"</string>
+ <string name="full_name" msgid="6602579550613988977">"Vardas"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Priešvardis"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Antras vardas"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Povardis"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Fonetinis vardas"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetinis antrasis vardas"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefonas"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"El. paštas"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adresas"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"TP"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizacija"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Ryšys"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Teksto pranešimas"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adresas"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Įmonė"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Pareigos"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Pastabos"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Svetainė"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Namų el. paštas"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Siųsti el. laišką mobiliuoju el. pašto adresu"</string>
+ <string name="email_work" msgid="2807430017302722689">"Siųsti el. laišką į darbo el. paštą"</string>
+ <string name="email_other" msgid="3454004077967657109">"El. paštas"</string>
+ <string name="email_custom" msgid="7548003991586214105">"El. paštas <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Siųsti el. paštu"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Gatvė"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Pašto dėžutė"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Kaimynystė"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Miestas"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Būsena"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Pašto kodas"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Šalis"</string>
+ <string name="map_home" msgid="1243547733423343982">"Žiūrėti namų adresą"</string>
+ <string name="map_work" msgid="1360474076921878088">"Žiūrėti darbo adresą"</string>
+ <string name="map_other" msgid="3817820803587012641">"Žiūrėti adresą"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Peržiūrėti <xliff:g id="CUSTOM">%s</xliff:g> adresą"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Kalbėti naudojant AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Kalbėti naudojant „Windows Live“"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Kalbėti naudojant „Yahoo“"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Kalbėti naudojant „Skype“"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Kalbėti naudojant QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Kalbėti naudojant „Google“ pokalbius"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Kalbėti naudojant ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Kalbėti naudojant „Jabber“"</string>
+ <string name="chat" msgid="9025361898797412245">"Kalbėti"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"ištrinti"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Išskleisti arba sutraukti pavadinimų laukus"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Visi kontaktai"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Pažymėta žvaigždute"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Tinkinti"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontaktas"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Visi kiti kontaktai"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Visi kontaktai"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Pašalinti sinchronizuojamą grupę"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Pridėti sinchronizuotą grupę"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Daugiau grupių..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Iš sinchronizavimo pašalinus „<xliff:g id="GROUP">%s</xliff:g>“, bus pašalinti ir nesugrupuoti kontaktai."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Išsaugomos pateikties parinktys..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Atlikta"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Atšaukti"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importuoti iš SIM kortelės"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Atšaukti <xliff:g id="FILENAME">%s</xliff:g> importavimą?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Atšaukti <xliff:g id="FILENAME">%s</xliff:g> eksportavimą?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Nepavyko atš. „vCard“ imp. / eksp."</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Nežinoma klaida."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Nepavyko atidaryti „<xliff:g id="FILE_NAME">%s</xliff:g>“: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Nepavyko inicijuoti eksportavimo priemonės: „<xliff:g id="EXACT_REASON">%s</xliff:g>“."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Nėra eksportuojamo kontakto."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Eksportuojant įvyko klaida: „<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Reikalingo failo pavadinimas per ilgas („<xliff:g id="FILENAME">%s</xliff:g>“)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Įvesties / išvesties klaida"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Nepakanka atminties. Gali būti, kad failas per didelis."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Dėl netikėtos priežasties nepavyko išanalizuoti el. vizitinės kortelės."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Formatas nepalaikomas."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Nepavyko surinkti pateikto (-ų) „vCard“ failo (-ų) metainformacijos."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Nepavyko importuoti vieno ar daugiau failų (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Baigta eksportuoti „<xliff:g id="FILENAME">%s</xliff:g>“."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> eksportavimas atšauktas."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Eksportuojami adresatų duomenys"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Nepavyko gauti duomenų bazės informacijos."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Nėra eksportuojamų kontaktų. Jei telefone yra kontaktų, kai kurie duomenų paslaugų teikėjai gali neleisti eksportuoti kontaktų iš telefono."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"El. vizitinių kortelių rengyklė nebuvo tinkamai paleista."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Nepavyko eksportuoti"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Kontakto duomenys nebuvo eksportuoti.\nPriežastis: „<xliff:g id="FAIL_REASON">%s</xliff:g>“"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importuojama <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Nepavyko nuskaityti „vCard“ duomenų"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"El. vizit. kort. duomenų skaitymas atš."</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Baigtas „<xliff:g id="FILENAME">%s</xliff:g>“ el. vizitinės kortelės importavimas"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Atšauktas <xliff:g id="FILENAME">%s</xliff:g> importavimas"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> bus netrukus importuotas."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Failas bus netrukus importuotas."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"El. vizitinės kortelės importavimo užklausa atmesta. Bandykite vėliau."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> bus netrukus eksportuotas."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"El. vizitinės kortelės eksportavimo užklausa buvo atmesta. Bandykite vėliau."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontaktas"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"El. vizitinė (-ės) kortelė (-ės) padedama (-os) į vietinę laikinąją atmintinę. Netrukus bus pradėtas tikrasis importavimas."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Nepavyko importuoti el. vizit. kortelės."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Gauta per ALR"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Eksp. kontaktus?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Dedama į talpyklą…"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importuojama <xliff:g id="CURRENT_NUMBER">%s</xliff:g> / <xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Nustatymai"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Bendrinti matomus adresatus"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Import. / eksport. kont."</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importuoti kontaktus"</string>
+ <string name="share_error" msgid="948429331673358107">"Šio kontakto negalima bendrinti."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Ieškoti"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Pateiktini kontaktai"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Pateiktini kontaktai"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Adresynas"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Kontaktų nėra."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Valyti dažniausiai naudojamus"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Pasirinkti SIM kortelę"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importuoti / eksportuoti"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Užblokuoti numeriai"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"naudojant „<xliff:g id="SOURCE">%1$s</xliff:g>“"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> naudojant „<xliff:g id="SOURCE">%2$s</xliff:g>“"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Išvalyti paiešką"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 0bee0f6..a887e41 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -239,9 +239,9 @@
<string name="set_default" msgid="4417505153468300351">"Iestatīt kā noklusējumu"</string>
<string name="clear_default" msgid="7193185801596678067">"Notīrīt noklusējuma iestatījumus"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Teksts ir nokopēts"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Vai atmest veiktās izmaiņas un beigt rediģēšanu?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Vai atmest izmaiņas?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Atmest"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Turpināt rediģēšanu"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Atcelt"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> — <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Meklēt kontaktpersonas"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Kontaktpersonu noņemšana"</string>
@@ -266,7 +266,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Par"</string>
<string name="send_message" msgid="8938418965550543196">"Sūtīt ziņojumu"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Notiek personīgā eksemplāra izveide..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Vakar"</string>
<string name="tomorrow" msgid="6241969467795308581">"Rīt"</string>
<string name="today" msgid="8041090779381781781">"Šodien"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Šodien plkst. <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -353,4 +352,335 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Ziņojumi"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Kārtojiet savu sarakstu"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Dzēsiet dublikātus un grupējiet kontaktpersonas pēc iezīmes."</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Teksts ir nokopēts"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopēt starpliktuvē"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Zvanīt: <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Zvanīt uz mājas numuru"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Zvanīt uz mobilo tālruni"</string>
+ <string name="call_work" msgid="5328785911463744028">"Zvanīt uz darba numuru"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Zvanīt uz darba faksa numuru"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Zvanīt uz mājas faksa numuru"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Zvanīt uz peidžeru"</string>
+ <string name="call_other" msgid="8563753966926932052">"Zvanīt"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Zvanīt uz atzvana numuru"</string>
+ <string name="call_car" msgid="3280537320306436445">"Zvanīt uz automobili"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Zvanīt uz uzņēmuma galveno tālruņa numuru"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Zvanīt uz ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Zvanīt uz galveno tālruņa numuru"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Zvanīt uz faksu"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Zvanīt uz radioierīci"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Zvanīt uz teleksu"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Zvanīt uz teletaipu/surdotālruni"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Zvanīt uz darba mobilo tālruni"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Zvanīt uz darba peidžeru"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Zvanīt: <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Zvanīt uz multiziņas numuru"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Sūtīt īsziņu uz <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Sūtīt īsziņu uz mājas tālruņa numuru"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Sūtīt īsziņu uz mobilo tālruni"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Sūtīt īsziņu uz darba numuru"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Sūtīt īsziņu uz darba faksa numuru"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Sūtīt īsziņu uz mājas faksa numuru"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Sūtīt īsziņu uz peidžeru"</string>
+ <string name="sms_other" msgid="806127844607642331">"Sūtīt īsziņu"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Sūtīt īsziņu uz atzvana numuru"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Sūtīt īsziņu uz automobiļa numuru"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Sūtīt īsziņu uz uzņēmuma galveno tālruņa numuru"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Sūtīt īsziņu uz ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Sūtīt īsziņu uz galveno tālruņa numuru"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Sūtīt īsziņu uz faksu"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Sūtīt īsziņu uz radioierīci"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Sūtīt īsziņu uz teleksa numuru"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Sūtīt īsziņu uz teletaipu/surdotālruni"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Sūtīt īsziņu uz darba mobilo tālruni"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Sūtīt īsziņu uz darba peidžeru"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Sūtīt īsziņu: <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Sūtīt multiziņu"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Vai dzēst bieži lietotos kontaktus?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Bieži lietoto kontaktu dzēšana..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Pieejama"</string>
+ <string name="status_away" msgid="1838861100379804730">"Prombūtnē"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Aizņemts"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontaktpersonas"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Cits"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Katalogs"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Visas kontaktpersonas"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Notiek meklēšana..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Ir atrastas vairāk nekā <xliff:g id="COUNT">%d</xliff:g> kontaktpersonas."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Nav kontaktpersonu"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="zero">Atrastas <xliff:g id="COUNT">%d</xliff:g> kontaktpersonas</item>
+ <item quantity="one">Atrasta <xliff:g id="COUNT">%d</xliff:g> kontaktpersona</item>
+ <item quantity="other">Atrastas <xliff:g id="COUNT">%d</xliff:g> kontaktpersonas</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Ātrā saziņa ar kontaktpersonu <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(nav vārda)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Bieža saziņa"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Skatīt kontaktpersonu"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Visas kontaktpersonas ar tālruņa numuriem"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Skatīt atjaunināj."</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Vārds"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Segvārds"</string>
+ <string name="full_name" msgid="6602579550613988977">"Vārds"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Uzruna"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Otrais vārds"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Uzruna"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Vārda izruna"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Otrā vārda izruna"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Tālrunis"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-pasts"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adrese"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Tūlītējā ziņojumapmaiņa"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizācija"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Saistība"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Īsziņa"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adrese"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Uzņēmums"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Nosaukums"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Piezīmes"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Vietne"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Sūtīt e-pasta ziņojumu uz privāto adresi"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Sūtīt e-pasta ziņojumu uz mobilo tālruni"</string>
+ <string name="email_work" msgid="2807430017302722689">"Sūtīt e-pasta ziņojumu uz darba adresi"</string>
+ <string name="email_other" msgid="3454004077967657109">"Sūtīt e-pasta ziņojumu"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Sūtīt e-pasta ziņojumu uz <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Sūtīt e-pasta ziņojumu"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Iela"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Abonenta kastīte"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Apkaime"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Pilsēta"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Štats"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Pasta indekss"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Valsts"</string>
+ <string name="map_home" msgid="1243547733423343982">"Skatīt mājas adresi"</string>
+ <string name="map_work" msgid="1360474076921878088">"Skatīt darba adresi"</string>
+ <string name="map_other" msgid="3817820803587012641">"Skatīt adresi"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Skatīt adresi: <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Tērzēt, izmantojot AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Tērzēt, izmantojot Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Tērzēt, izmantojot Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Tērzēt, izmantojot Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Tērzēt, izmantojot QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Tērzēt, izmantojot Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Tērzēt, izmantojot ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Tērzēt, izmantojot Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Tērzēt"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"dzēst"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Izvērst vai sakļaut nosaukumu laukus"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Visas kontaktpersonas"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Atzīmēts ar zvaigznīti"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Pielāgot"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontaktpersona"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Citas kontaktpersonas"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Visas kontaktpersonas"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Noņemt sinhronizējamo grupu"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Pievienot sinhronizējamu grupu"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Vairāk grupu..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Pārtraucot grupas <xliff:g id="GROUP">%s</xliff:g> sinhronizāciju, tiks pārtraukta arī visu negrupēto kontaktpersonu sinhronizācija."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Notiek attēlojuma opciju saglabāšana..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Gatavs"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Atcelt"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importēt no SIM kartes"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Vai atcelt faila <xliff:g id="FILENAME">%s</xliff:g> importēšanu?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Vai atcelt faila <xliff:g id="FILENAME">%s</xliff:g> eksportēšanu?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Nevarēja atcelt vCard f. import./eksp."</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Nezināma kļūda."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Nevarēja atvērt failu <xliff:g id="FILE_NAME">%s</xliff:g>: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Nevarēja startēt eksportētāju: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Nav nevienas eksportējamas kontaktpersonas."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Eksportēšanas laikā radās kļūda: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Faila nosaukums ir pārāk garš (<xliff:g id="FILENAME">%s</xliff:g>)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Ievades/izvades kļūda."</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Atmiņā nepietiek vietas. Iespējams, fails ir pārāk liels."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Neparedzēta iemesla dēļ nevarēja parsēt vCard failu."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Šāds formāts netiek atbalstīts."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Nevarēja iegūt metainformāciju par konkrēto(-ajiem) vCard failu(-iem)."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Nevarēja importēt vienu vai vairākus failus (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Faila <xliff:g id="FILENAME">%s</xliff:g> eksportēšana pabeigta"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Faila <xliff:g id="FILENAME">%s</xliff:g> eksportēšana atcelta"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Kontaktpersonu datu eksportēšana"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Nevarēja iegūt informāciju no datu bāzes."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Nav nevienas eksportējamas kontaktpersonas. Ja jūsu tālrunī ir saglabātas kontaktpersonas, iespējams, jūsu datu pakalpojumu sniedzējs neļauj eksportēt kontaktpersonas no tālruņa."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Netika pareizi startēts vCard veidotājs."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Nevarēja eksportēt"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Kontaktpersonas dati netika eksportēti.\nIemesls: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Notiek imp.: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Nevarēja nolasīt vCard datus."</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Atcelta vCard datu lasīšana"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard faila <xliff:g id="FILENAME">%s</xliff:g> importēšana ir pabeigta"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Faila <xliff:g id="FILENAME">%s</xliff:g> importēšana atcelta"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Fails <xliff:g id="FILENAME">%s</xliff:g> tiks drīzumā importēts."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Fails drīzumā tiks importēts."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Tika noraidīts vCard faila importēšanas pieprasījums. Vēlāk mēģiniet vēlreiz."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Fails <xliff:g id="FILENAME">%s</xliff:g> tiks drīzumā eksportēts."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Tika noraidīts vCard faila eksportēšanas pieprasījums. Vēlāk mēģiniet vēlreiz."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontaktpersona"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Notiek vCard failu saglabāšana vietējā pagaidu atmiņā. Importēšana tiks sākta pēc neilga brīža."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Nevarēja importēt vCard datus."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"No NFC saņ. kontaktinf."</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Vai eksp. kontaktp.?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Notiek saglabāšana kešatmiņā"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importē <xliff:g id="CURRENT_NUMBER">%s</xliff:g> no <xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Iestatījumi"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Kopīgot redzamās kontaktpersonas"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"K. pers. imports/eksports"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Kontaktpersonu importēšana"</string>
+ <string name="share_error" msgid="948429331673358107">"Šo kontaktpersonu nevar kopīgot."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Meklēt"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Attēlojamās kontaktpersonas"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Attēlojamās kontaktpers."</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Izlase"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Nav kontaktpersonu."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Dzēst bieži lietotos kontaktus"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Atlasiet SIM karti"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importēt/eksportēt"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Bloķētie numuri"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"izmantojot <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g>, izmantojot <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Notīrīt meklēšanas lauku"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
index 8e34554..23a44ba 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Постави стандарден метод"</string>
<string name="clear_default" msgid="7193185801596678067">"Исчисти стандарден метод"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Текстот е копиран"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Дали да се отфрлат промените и да се прекине уредувањето?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Да се отфрлат промените?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Отфрли"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Продолжи со уредување"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Откажи"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Пребарајте контакти"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Отстрани контакти"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"За"</string>
<string name="send_message" msgid="8938418965550543196">"Испрати порака"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Се создава лична копија..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Вчера"</string>
<string name="tomorrow" msgid="6241969467795308581">"Утре"</string>
<string name="today" msgid="8041090779381781781">"Денес"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Денес во <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,505 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Пораки"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Организирајте го списокот"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Исчистете ги дупликатите и групните контакти според етикетата"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Текстот е копиран"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Копирај во клип-табла"</string>
+ <!-- no translation found for call_custom (7756571794763171802) -->
+ <skip />
+ <!-- no translation found for call_home (1990519474420545392) -->
+ <skip />
+ <!-- no translation found for call_mobile (7502236805487609178) -->
+ <skip />
+ <!-- no translation found for call_work (5328785911463744028) -->
+ <skip />
+ <!-- no translation found for call_fax_work (7467763592359059243) -->
+ <skip />
+ <!-- no translation found for call_fax_home (8342175628887571876) -->
+ <skip />
+ <!-- no translation found for call_pager (9003902812293983281) -->
+ <skip />
+ <!-- no translation found for call_other (8563753966926932052) -->
+ <skip />
+ <!-- no translation found for call_callback (1910165691349426858) -->
+ <skip />
+ <!-- no translation found for call_car (3280537320306436445) -->
+ <skip />
+ <!-- no translation found for call_company_main (6105120947138711257) -->
+ <skip />
+ <!-- no translation found for call_isdn (1541590690193403411) -->
+ <skip />
+ <!-- no translation found for call_main (6082900571803441339) -->
+ <skip />
+ <!-- no translation found for call_other_fax (5745314124619636674) -->
+ <skip />
+ <!-- no translation found for call_radio (8296755876398357063) -->
+ <skip />
+ <!-- no translation found for call_telex (2223170774548648114) -->
+ <skip />
+ <!-- no translation found for call_tty_tdd (8951266948204379604) -->
+ <skip />
+ <!-- no translation found for call_work_mobile (8707874281430105394) -->
+ <skip />
+ <!-- no translation found for call_work_pager (3419348514157949008) -->
+ <skip />
+ <!-- no translation found for call_assistant (2141641383068514308) -->
+ <skip />
+ <!-- no translation found for call_mms (6274041545876221437) -->
+ <skip />
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <!-- no translation found for sms_custom (5932736853732191825) -->
+ <skip />
+ <!-- no translation found for sms_home (7524332261493162995) -->
+ <skip />
+ <!-- no translation found for sms_mobile (5200107250451030769) -->
+ <skip />
+ <!-- no translation found for sms_work (2269624156655267740) -->
+ <skip />
+ <!-- no translation found for sms_fax_work (8028189067816907075) -->
+ <skip />
+ <!-- no translation found for sms_fax_home (9204042076306809634) -->
+ <skip />
+ <!-- no translation found for sms_pager (7730404569637015192) -->
+ <skip />
+ <!-- no translation found for sms_other (806127844607642331) -->
+ <skip />
+ <!-- no translation found for sms_callback (5004824430094288752) -->
+ <skip />
+ <!-- no translation found for sms_car (7444227058437359641) -->
+ <skip />
+ <!-- no translation found for sms_company_main (118970873419678087) -->
+ <skip />
+ <!-- no translation found for sms_isdn (8153785037515047845) -->
+ <skip />
+ <!-- no translation found for sms_main (8621625784504541679) -->
+ <skip />
+ <!-- no translation found for sms_other_fax (3888842199855843152) -->
+ <skip />
+ <!-- no translation found for sms_radio (3329166673433967820) -->
+ <skip />
+ <!-- no translation found for sms_telex (9034802430065267848) -->
+ <skip />
+ <!-- no translation found for sms_tty_tdd (6782284969132531532) -->
+ <skip />
+ <!-- no translation found for sms_work_mobile (2459939960512702560) -->
+ <skip />
+ <!-- no translation found for sms_work_pager (5566924423316960597) -->
+ <skip />
+ <!-- no translation found for sms_assistant (2773424339923116234) -->
+ <skip />
+ <!-- no translation found for sms_mms (4069352461380762677) -->
+ <skip />
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation_title (766292372438450432) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <!-- no translation found for clearFrequentsProgress_title (5157001637482794212) -->
+ <skip />
+ <!-- no translation found for status_available (5586870015822828392) -->
+ <skip />
+ <!-- no translation found for status_away (1838861100379804730) -->
+ <skip />
+ <!-- no translation found for status_busy (9147992455450257136) -->
+ <skip />
+ <string name="contactsList" msgid="8661624236494819731">"Контакти"</string>
+ <!-- no translation found for local_invisible_directory (6046691709127661065) -->
+ <skip />
+ <!-- no translation found for directory_search_label (1887759056597975053) -->
+ <skip />
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <!-- no translation found for local_search_label (2551177578246113614) -->
+ <skip />
+ <string name="search_results_searching" msgid="3984833028938569930">"Се пребарува..."</string>
+ <!-- no translation found for foundTooManyContacts (5163335650920020220) -->
+ <skip />
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Нема контакти"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> пронајден</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> пронајдени</item>
+ </plurals>
+ <!-- no translation found for description_quick_contact_for (6737516415168327789) -->
+ <skip />
+ <!-- no translation found for missing_name (8745511583852904385) -->
+ <skip />
+ <!-- no translation found for favoritesFrequentContacted (6184232487472425690) -->
+ <skip />
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Прикажи контакт"</string>
+ <!-- no translation found for list_filter_phones (735313795643493365) -->
+ <skip />
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <!-- no translation found for view_updates_from_group (1782685984905600034) -->
+ <skip />
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <!-- no translation found for nameLabelsGroup (2034640839640477827) -->
+ <skip />
+ <!-- no translation found for nicknameLabelsGroup (2891682101053358010) -->
+ <skip />
+ <!-- no translation found for full_name (6602579550613988977) -->
+ <skip />
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <!-- no translation found for name_prefix (59756378548779822) -->
+ <skip />
+ <!-- no translation found for name_middle (8467433655992690326) -->
+ <skip />
+ <!-- no translation found for name_suffix (3855278445375651441) -->
+ <skip />
+ <!-- no translation found for name_phonetic (4259595234312430484) -->
+ <skip />
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <!-- no translation found for name_phonetic_middle (8643721493320405200) -->
+ <skip />
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <!-- no translation found for phoneLabelsGroup (6468091477851199285) -->
+ <skip />
+ <!-- no translation found for emailLabelsGroup (8389931313045344406) -->
+ <skip />
+ <!-- no translation found for postalLabelsGroup (3487738141112589324) -->
+ <skip />
+ <!-- no translation found for imLabelsGroup (3898238486262614027) -->
+ <skip />
+ <!-- no translation found for organizationLabelsGroup (2478611760751832035) -->
+ <skip />
+ <!-- no translation found for relationLabelsGroup (1854373894284572781) -->
+ <skip />
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <!-- no translation found for sms (1756857139634224222) -->
+ <skip />
+ <!-- no translation found for postal_address (8765560217149624536) -->
+ <skip />
+ <!-- no translation found for ghostData_company (5414421120553765775) -->
+ <skip />
+ <!-- no translation found for ghostData_title (7496735200318496110) -->
+ <skip />
+ <!-- no translation found for label_notes (8337354953278341042) -->
+ <skip />
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <!-- no translation found for websiteLabelsGroup (4202998982804009261) -->
+ <skip />
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <!-- no translation found for email_home (8573740658148184279) -->
+ <skip />
+ <!-- no translation found for email_mobile (2042889209787989814) -->
+ <skip />
+ <!-- no translation found for email_work (2807430017302722689) -->
+ <skip />
+ <!-- no translation found for email_other (3454004077967657109) -->
+ <skip />
+ <!-- no translation found for email_custom (7548003991586214105) -->
+ <skip />
+ <!-- no translation found for email (5668400997660065897) -->
+ <skip />
+ <!-- no translation found for postal_street (8133143961580058972) -->
+ <skip />
+ <!-- no translation found for postal_pobox (4431938829180269821) -->
+ <skip />
+ <!-- no translation found for postal_neighborhood (1450783874558956739) -->
+ <skip />
+ <!-- no translation found for postal_city (6597491300084895548) -->
+ <skip />
+ <!-- no translation found for postal_region (6045263193478437672) -->
+ <skip />
+ <!-- no translation found for postal_postcode (572136414136673751) -->
+ <skip />
+ <!-- no translation found for postal_country (7638264508416368690) -->
+ <skip />
+ <!-- no translation found for map_home (1243547733423343982) -->
+ <skip />
+ <!-- no translation found for map_work (1360474076921878088) -->
+ <skip />
+ <!-- no translation found for map_other (3817820803587012641) -->
+ <skip />
+ <!-- no translation found for map_custom (6184363799976265281) -->
+ <skip />
+ <!-- no translation found for chat_aim (2588492205291249142) -->
+ <skip />
+ <!-- no translation found for chat_msn (8041633440091073484) -->
+ <skip />
+ <!-- no translation found for chat_yahoo (6629211142719943666) -->
+ <skip />
+ <!-- no translation found for chat_skype (1210045020427480566) -->
+ <skip />
+ <!-- no translation found for chat_qq (4294637812847719693) -->
+ <skip />
+ <!-- no translation found for chat_gtalk (981575737258117697) -->
+ <skip />
+ <!-- no translation found for chat_icq (8438405386153745775) -->
+ <skip />
+ <!-- no translation found for chat_jabber (7561444230307829609) -->
+ <skip />
+ <!-- no translation found for chat (9025361898797412245) -->
+ <skip />
+ <!-- no translation found for description_minus_button (6908099247930477551) -->
+ <skip />
+ <!-- no translation found for expand_collapse_name_fields_description (8682630859539604311) -->
+ <skip />
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <!-- no translation found for list_filter_all_accounts (8908683398914322369) -->
+ <skip />
+ <!-- no translation found for list_filter_all_starred (5031734941601931356) -->
+ <skip />
+ <!-- no translation found for list_filter_customize (4789963356004169321) -->
+ <skip />
+ <!-- no translation found for list_filter_single (5871400283515893087) -->
+ <skip />
+ <!-- no translation found for display_ungrouped (6885954210243119591) -->
+ <skip />
+ <!-- no translation found for display_all_contacts (2031647544742889505) -->
+ <skip />
+ <!-- no translation found for menu_sync_remove (3266725887008450161) -->
+ <skip />
+ <!-- no translation found for dialog_sync_add (8267045393119375803) -->
+ <skip />
+ <!-- no translation found for display_more_groups (2682547080423434170) -->
+ <skip />
+ <!-- no translation found for display_warn_remove_ungrouped (8872290721676651414) -->
+ <skip />
+ <!-- no translation found for savingDisplayGroups (2133152192716475939) -->
+ <skip />
+ <!-- no translation found for menu_done (796017761764190697) -->
+ <skip />
+ <!-- no translation found for menu_doNotSave (58593876893538465) -->
+ <skip />
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <!-- no translation found for import_from_sim (3859272228033941659) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <!-- no translation found for cancel_import_confirmation_message (3929951040347726757) -->
+ <skip />
+ <!-- no translation found for cancel_export_confirmation_message (1995462401949262638) -->
+ <skip />
+ <!-- no translation found for cancel_vcard_import_or_export_failed (6139900383366166706) -->
+ <skip />
+ <!-- no translation found for fail_reason_unknown (1714092345030570863) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_open_file (2067725459821997463) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_initialize_exporter (707260459259688510) -->
+ <skip />
+ <!-- no translation found for fail_reason_no_exportable_contact (8728506011371262065) -->
+ <skip />
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <!-- no translation found for fail_reason_error_occurred_during_export (3018855323913649063) -->
+ <skip />
+ <!-- no translation found for fail_reason_too_long_filename (3393764245254738333) -->
+ <skip />
+ <!-- no translation found for fail_reason_io_error (6748358842976073255) -->
+ <skip />
+ <!-- no translation found for fail_reason_low_memory_during_import (875222757734882898) -->
+ <skip />
+ <!-- no translation found for fail_reason_vcard_parse_error (888263542360355784) -->
+ <skip />
+ <!-- no translation found for fail_reason_not_supported (8219562769267148825) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_collect_vcard_meta_info (6427931733267328564) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title (4767045779458185251) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_canceled_title (2652222370493306887) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <!-- no translation found for composer_failed_to_get_database_infomation (1765944280846236723) -->
+ <skip />
+ <!-- no translation found for composer_has_no_exportable_contact (3296493229040294335) -->
+ <skip />
+ <!-- no translation found for composer_not_initialized (2321648986367005254) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_title (4892358112409576342) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_message (4938527850142003141) -->
+ <skip />
+ <!-- no translation found for importing_vcard_description (4245275224298571351) -->
+ <skip />
+ <!-- no translation found for reading_vcard_failed_title (4251647443358422855) -->
+ <skip />
+ <!-- no translation found for reading_vcard_canceled_title (1925216585981542019) -->
+ <skip />
+ <!-- no translation found for importing_vcard_finished_title (3341541727268747967) -->
+ <skip />
+ <!-- no translation found for importing_vcard_canceled_title (2147475978165599336) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message (2804911199145873396) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message_with_default_name (1022969530654129470) -->
+ <skip />
+ <!-- no translation found for vcard_import_request_rejected_message (2890471184508516011) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message (2210241345252081463) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <!-- no translation found for vcard_export_request_rejected_message (2844874826431327531) -->
+ <skip />
+ <!-- no translation found for vcard_unknown_filename (7171709890959915954) -->
+ <skip />
+ <!-- no translation found for caching_vcard_message (4926308675041506756) -->
+ <skip />
+ <!-- no translation found for vcard_import_failed (5223531255894842406) -->
+ <skip />
+ <!-- no translation found for nfc_vcard_file_name (2823095213265993609) -->
+ <skip />
+ <!-- no translation found for confirm_export_title (6834385377255286349) -->
+ <skip />
+ <!-- no translation found for caching_vcard_title (1226272312940516605) -->
+ <skip />
+ <!-- no translation found for progress_notifier_message (2311011466908220528) -->
+ <skip />
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Поставки"</string>
+ <!-- no translation found for share_visible_contacts (890150378880783797) -->
+ <skip />
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <!-- no translation found for dialog_import_export (4360648034889921624) -->
+ <skip />
+ <!-- no translation found for dialog_import (2431698729761448759) -->
+ <skip />
+ <!-- no translation found for share_error (948429331673358107) -->
+ <skip />
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <!-- no translation found for menu_search (9147752853603483719) -->
+ <skip />
+ <!-- no translation found for menu_contacts_filter (2165153460860262501) -->
+ <skip />
+ <!-- no translation found for activity_title_contacts_filter (8275542497615516969) -->
+ <skip />
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <!-- no translation found for contactsFavoritesLabel (8417039765586853670) -->
+ <skip />
+ <!-- no translation found for listTotalAllContactsZero (5513001821794568211) -->
+ <skip />
+ <!-- no translation found for menu_clear_frequents (7688250191932838833) -->
+ <skip />
+ <string name="menu_select_sim" msgid="3603578201960504010">"Изберете СИМ-картичка"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <!-- no translation found for menu_import_export (26217871113229507) -->
+ <skip />
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Блокирани броеви"</string>
+ <!-- no translation found for contact_status_update_attribution (752179367353018597) -->
+ <skip />
+ <!-- no translation found for contact_status_update_attribution_with_date (7358045508107825068) -->
+ <skip />
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Исчисти го полето за пребарување"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index 76c72ba..a1d0e05 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"സ്ഥിരമായി സജ്ജമാക്കുക"</string>
<string name="clear_default" msgid="7193185801596678067">"സ്ഥിരമായത് മായ്ക്കുക"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"വാചകം പകർത്തി"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"നിങ്ങളുടെ മാറ്റങ്ങൾ തള്ളിക്കളയുകയും എഡിറ്റുചെയ്യൽ ഉപേക്ഷിക്കുകയും ചെയ്യണോ?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"മാറ്റങ്ങൾ നിരസിക്കണോ?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"തള്ളിക്കളയുക"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"എഡിറ്റുചെയ്യുന്നത് തുടരുക"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"റദ്ദാക്കൂ"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"കോണ്ടാക്റ്റുകള് തിരയുക"</string>
<string name="title_edit_group" msgid="8602752287270586734">"കോൺടാക്റ്റുകൾ നീക്കംചെയ്യുക"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"ആമുഖം"</string>
<string name="send_message" msgid="8938418965550543196">"സന്ദേശം അയയ്ക്കുക"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"ഒരു വ്യക്തിഗത പകർപ്പ് സൃഷ്ടിക്കുന്നു…"</string>
- <string name="yesterday" msgid="6840858548955018569">"ഇന്നലെ"</string>
<string name="tomorrow" msgid="6241969467795308581">"നാളെ"</string>
<string name="today" msgid="8041090779381781781">"ഇന്ന്"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"ഇന്ന് <xliff:g id="TIME_INTERVAL">%s</xliff:g> മണിയ്ക്ക്"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"സന്ദേശങ്ങള്"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"നിങ്ങളുടെ ലിസ്റ്റ് ഓർഗനൈസുചെയ്യുക"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"ലേബൽ പ്രകാരം ഡ്യൂപ്ലിക്കേറ്റുകളും ഗ്രൂപ്പ് കോൺടാക്റ്റുകളും മായ്ക്കുക"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"വാചകം പകർത്തി"</string>
+ <string name="copy_text" msgid="3257145021583508761">"ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തുക"</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="8563753966926932052">"വിളിക്കുക"</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="5745314124619636674">"ഫാക്സിലേക്ക് വിളിക്കുക"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"വാചകസന്ദേശം"</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="3888842199855843152">"ഫാക്സിലേക്ക് വാചകസന്ദേശമയയ്ക്കുക"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"പതിവായി കോൺടാക്റ്റുചെയ്യുന്നവരെ മായ്ക്കണോ?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"പതിവായി കോൺടാക്റ്റുചെയ്യുന്നവരെ മായ്ക്കുന്നു…"</string>
+ <string name="status_available" msgid="5586870015822828392">"ലഭ്യം"</string>
+ <string name="status_away" msgid="1838861100379804730">"ലഭ്യമല്ല"</string>
+ <string name="status_busy" msgid="9147992455450257136">"തിരക്കിൽ"</string>
+ <string name="contactsList" msgid="8661624236494819731">"വിലാസങ്ങൾ"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"മറ്റുള്ളവ"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"ഡയറക്ടറി"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"എല്ലാ കോൺടാക്റ്റുകളും"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"തിരയുന്നു…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g>-ൽ കൂടുതൽ കണ്ടെത്തി."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"കോൺടാക്റ്റുകളൊന്നുമില്ല"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> എണ്ണം കണ്ടെത്തി</item>
+ <item quantity="one">ഒന്ന് കണ്ടെത്തി</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> എന്നയാളുടെ ദ്രുത കോൺടാക്റ്റ്"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(പേരില്ല)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"പതിവായി കോൺടാക്റ്റുചെയ്യുന്നവർ"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"കോൺടാക്റ്റ് കാണുക"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"ഫോൺ നമ്പറുകളുള്ള എല്ലാ കോൺടാക്റ്റുകളും"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"അപ്ഡേറ്റുകള് കാണുക"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"പേര്"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"വിളിപ്പേര്"</string>
+ <string name="full_name" msgid="6602579550613988977">"പേര്"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"ഉച്ചാരണപ്രകാരമുള്ള പേര്"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"ഉച്ചാരണപ്രകാരമുള്ള പേരിന്റെ മധ്യഭാഗം"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"ഫോണ്"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"ഇമെയില്"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"വിലാസം"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"ഓര്ഗനൈസേഷന്"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"ബന്ധം"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"വാചക സന്ദേശം"</string>
+ <string name="postal_address" msgid="8765560217149624536">"വിലാസം"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"കമ്പനി"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"ശീർഷകം"</string>
+ <string name="label_notes" msgid="8337354953278341042">"കുറിപ്പുകള്"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"വെബ്സൈറ്റ്"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"ഇമെയില്"</string>
+ <string name="email_custom" msgid="7548003991586214105">"<xliff:g id="CUSTOM">%s</xliff:g> എന്നതിലേക്ക് ഇമെയിൽ ചെയ്യുക"</string>
+ <string name="email" msgid="5668400997660065897">"ഇമെയില്"</string>
+ <string name="postal_street" msgid="8133143961580058972">"സ്ട്രീറ്റ്"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO ബോക്സ്"</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="map_home" msgid="1243547733423343982">"വീട്ടുവിലാസം കാണുക"</string>
+ <string name="map_work" msgid="1360474076921878088">"ഔദ്യോഗിക വിലാസം കാണുക"</string>
+ <string name="map_other" msgid="3817820803587012641">"വിലാസം കാണുക"</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="description_minus_button" msgid="6908099247930477551">"ഇല്ലാതാക്കുക"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"പേരിന്റെ ഫീൽഡുകൾ വിപുലീകരിക്കുക അല്ലെങ്കിൽ ചുരുക്കുക"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"എല്ലാ കോൺടാക്റ്റുകളും"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"നക്ഷത്രമിട്ടവ"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"ഇഷ്ടാനുസൃതമാക്കുക"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"കോൺടാക്റ്റ്"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"മറ്റെല്ലാ കോൺടാക്റ്റുകളും"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"എല്ലാ കോൺടാക്റ്റുകളും"</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_warn_remove_ungrouped" msgid="8872290721676651414">"സമന്വയത്തിൽ നിന്നും \"<xliff:g id="GROUP">%s</xliff:g>\" നീക്കംചെയ്യുന്നത്, സമന്വയത്തിൽ നിന്നും ഗ്രൂപ്പുചെയ്യാത്ത എല്ലാ കോൺടാക്റ്റുകളേയും നീക്കംചെയ്യുന്നതിനിടയാക്കും."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"ഡിസ്പ്ലേ ഓപ്ഷനുകൾ സംരക്ഷിക്കുന്നു…"</string>
+ <string name="menu_done" msgid="796017761764190697">"പൂർത്തിയായി"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"റദ്ദാക്കുക"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"സിം കാർഡിൽ നിന്നും ഇമ്പോർട്ടുചെയ്യുക"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> എന്നത് ഇമ്പോർട്ടുചെയ്യുന്നത് റദ്ദാക്കണോ?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> എന്നത് എക്സ്പോർട്ടുചെയ്യുന്നത് റദ്ദാക്കണോ?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard ഇമ്പോർട്ടുചെയ്യൽ/എക്സ്പോർട്ടുചെയ്യൽ റദ്ദാക്കാനായില്ല"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"അജ്ഞാത പിശക്."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" തുറക്കാനായില്ല: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"എക്സ്പോർട്ടർ ആരംഭിക്കാനായില്ല: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"എക്സ്പോർട്ടുചെയ്യാനാകുന്ന കോൺടാക്റ്റ് ഒന്നുമില്ല."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"എക്സ്പോർട്ടുചെയ്യുമ്പോൾ ഒരു പിശക് സംഭവിച്ചു: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"ആവശ്യമായ ഫയലിന്റെ പേര് ദൈർഘ്യമേറിയതാണ് (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O പിശക്"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"ആവശ്യമായ മെമ്മറിയില്ല. ഫയൽ വളരെ വലുതായിരിക്കാം."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"ഒരു അപ്രതീക്ഷിത കാരണത്താൽ vCard പാഴ്സുചെയ്യാനായില്ല."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"ഫോർമാറ്റിനെ പിന്തുണയ്ക്കില്ല."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"നൽകിയിരിക്കുന്ന vCard ഫയലിന്റെ (ഫയലുകളുടെ) മെറ്റ വിവരം ശേഖരിക്കാനായില്ല."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"ഒന്നോ അതിലധികമോ ഫയലുകൾ ഇമ്പോർട്ടുചെയ്യാനായില്ല (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> എക്സ്പോർട്ടുചെയ്യൽ പൂർത്തിയായി."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> എക്സ്പോർട്ടുചെയ്യൽ റദ്ദാക്കി."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"കോൺടാക്റ്റ് ഡാറ്റ എക്സ്പോർട്ടുചെയ്യുന്നു"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"ഡാറ്റാബേസ് വിവരം നേടാനായില്ല."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"എക്സ്പോർട്ടുചെയ്യാനാകുന്ന കോൺടാക്റ്റുകളൊന്നുമില്ല. നിങ്ങളുടെ ഫോണിൽ കോൺടാക്റ്റുകളുണ്ടെങ്കിൽ, ഫോണിൽ നിന്നും കോൺടാക്റ്റുകൾ എക്സ്പോർട്ടുചെയ്യാൻ ചില സേവന ദാതാക്കൾ അനുവദിക്കാനിടയില്ല."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard കമ്പോസർ ശരിയായി ആരംഭിച്ചില്ല."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"എക്സ്പോർട്ടുചെയ്യാനായില്ല"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"കോൺടാക്റ്റ് ഡാറ്റ എക്സ്പോർട്ടുചെയ്തില്ല.\nകാരണം: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> എന്നയാളെ ഇമ്പോർട്ടുചെയ്യുന്നു"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard ഡാറ്റ വായിക്കാനായില്ല"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard ഡാറ്റ വായിക്കുന്നത് റദ്ദാക്കി"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g> ഇമ്പോർട്ടുചെയ്യൽ പൂർത്തിയായി"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> ഇമ്പോർട്ടുചെയ്യൽ റദ്ദാക്കി"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> എന്നത് ഉടൻ ഇമ്പോർട്ടുചെയ്യും."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"ഫയൽ ഉടൻ ഇമ്പോർട്ടുചെയ്യും."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard ഇമ്പോർട്ടുചെയ്യൽ അഭ്യർത്ഥന നിരസിച്ചു. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> എന്നത് ഉടൻ എക്സ്പോർട്ടുചെയ്യും."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard എക്സ്പോർട്ടുചെയ്യൽ അഭ്യർത്ഥന നിരസിച്ചു. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"കോൺടാക്റ്റ്"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"പ്രാദേശിക താൽക്കാലിക സംഭരണത്തിലേക്ക് vCard (vCard-കൾ) കാഷെ ചെയ്യുന്നു. യഥാർത്ഥ ഇമ്പോർട്ടുചെയ്യൽ ഉടൻ ആരംഭിക്കും."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard ഇമ്പോർട്ടുചെയ്യാനായില്ല."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC മുഖേന ലഭിച്ച കോൺടാക്റ്റ്"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"കോൺടാക്റ്റുകൾ എക്സ്പോർട്ടുചെയ്യണോ?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"കാഷെ ചെയ്യൽ"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g> ഇമ്പോർട്ടുചെയ്യുന്നു: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"ക്രമീകരണം"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"ദൃശ്യമായ കോൺടാക്റ്റുകൾ പങ്കിടുക"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"കോൺടാക്റ്റുകൾ ഇമ്പോർട്ടുചെയ്യുക/എക്സ്പോർട്ടുചെയ്യുക"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"കോൺടാക്റ്റുകൾ ഇമ്പോർട്ടുചെയ്യുക"</string>
+ <string name="share_error" msgid="948429331673358107">"ഈ കോൺടാക്റ്റ് പങ്കിടാനാകില്ല."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"തിരയുക"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"ദൃശ്യമാക്കേണ്ട കോൺടാക്റ്റുകൾ"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"ദൃശ്യമാക്കേണ്ട കോൺടാക്റ്റുകൾ"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"പ്രിയപ്പെട്ടവ"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"കോൺടാക്റ്റുകൾ ഒന്നുമില്ല."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"പതിവായി കോൺടാക്റ്റുചെയ്യുന്നവരെ മായ്ക്കുക"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"സിം കാർഡ് തിരഞ്ഞെടുക്കുക"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"ഇമ്പോർട്ടുചെയ്യുക/എക്സ്പോർട്ടുചെയ്യുക"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"ബ്ലോക്കുചെയ്ത നമ്പറുകൾ"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g> വഴി"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="SOURCE">%2$s</xliff:g> വഴി <xliff:g id="DATE">%1$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"തിരയൽ മായ്ക്കുക"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
index 6396aa5..d2b2db2 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn-rMN/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Үндсэн болгох"</string>
<string name="clear_default" msgid="7193185801596678067">"Үндсэнээс хасах"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Текст хуулагдав"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Таны өөрчлөлтийн устгал, засварыг болих уу?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Өөрчлөлтийг цуцлах уу?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Устгах"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Үргэлжлүүлэн засах"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Цуцлах"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Харилцагчдаас хайх"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Харилцагчдыг арилгах"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Тухай"</string>
<string name="send_message" msgid="8938418965550543196">"Зурвас илгээх"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Хувийн хуулбар үүсгэж байна…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Өчигдөр"</string>
<string name="tomorrow" msgid="6241969467795308581">"Маргааш"</string>
<string name="today" msgid="8041090779381781781">"Өнөөдөр"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Өнөөдөр <xliff:g id="TIME_INTERVAL">%s</xliff:g>-д"</string>
@@ -342,4 +341,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Зурвас"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Жагсаалтаа цэгцэлнэ үү"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Давхардсан харилцагчдыг цэвэрлэж & шошгоор бүлэглэх"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Текст хуулагдав"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Түр санах ойд хуулах"</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="8563753966926932052">"Залгах"</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="5745314124619636674">"Факс руу залгах"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Зурвас илгээх"</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="3888842199855843152">"Факс руу зурвас илгээх"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Байнга холбоо барьдаг харилцагчдын жагсаалтыг устгах уу?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Байнга холбоо барьдаг харилцагчдын жагсаалтыг устгаж байна…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Холбогдсон"</string>
+ <string name="status_away" msgid="1838861100379804730">"Холдсон"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Завгүй"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Харилцагчид"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Бусад"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Директор"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Бүх харилцагчид"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Хайж байна..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g>-с олон олдлоо."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Харилцагч байхгүй"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> олдсон байна</item>
+ <item quantity="one">1 олсон байна</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g>-тай шууд холбогдох"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Нэр байхгүй)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Байнга холбоо барьдаг"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Харилцагчийг харах"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Утасны дугаартай бүх харилцагчид"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Шинэчлэлтүүдийг харах"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Нэр"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Хоч"</string>
+ <string name="full_name" msgid="6602579550613988977">"Нэр"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Авианы нэр"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Дундах авианы нэр"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Утас"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Имэйл"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Хаяг"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Байгууллага"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Хамаарал"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Зурвас"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Хаяг"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Компани"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Гарчиг"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Тэмдэглэл"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Вебсайт"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"Имэйл"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Имэйл <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Имэйл"</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="map_home" msgid="1243547733423343982">"Гэрийн хаяг харах"</string>
+ <string name="map_work" msgid="1360474076921878088">"Ажлын хаяг харах"</string>
+ <string name="map_other" msgid="3817820803587012641">"Хаяг харах"</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="description_minus_button" msgid="6908099247930477551">"устгах"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Нэрийн талбаруудыг дэлгэх буюу хумих"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Бүх харилцагчид"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Одтой"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Тохируулах"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Харилцагч"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Бусад бүх харилцагчид"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Бүх харилцагчид"</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_warn_remove_ungrouped" msgid="8872290721676651414">"\"<xliff:g id="GROUP">%s</xliff:g>\"-г синкээс хассанаар бүлгэмээс хасагдсан бүх харилцагчдыг мөн синкээс хасах болно."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Харуулах тохиргоог хадгалж байна…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Дууссан"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Цуцлах"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM картаас импорт хийх"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g>-г импорт хийхийг цуцлах уу?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g>-г экспорт хийхийг цуцлах уу?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard импорт/экспорт хийхийг цуцлаж чадсангүй"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Тодорхойгүй алдаа."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\"-г нээж чадсангүй: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Экспорт хийгчийг эхлүүлж чадсангүй: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Экспорт хийж болох харилцагч байхгүй."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Экспорт хийх явцад алдаа гарсан: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Шаардагдах файлын нэр хэт урт (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O алдаа"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Санах ой хүрэхгүй байна. Файл хэт том байж магадгүй."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Тодорхойгүй шалтгаанаар vCard-г задлаж чадсангүй."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Формат нь дэмжигдэхгүй байна."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Өгөгдсөн vCard файлын мета мэдээллийг цуглуулж чадсангүй."</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g>-г экспорт хийж дууссан."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g>-г экспорт хийхийг цуцлав."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Харилцагчийн өгөгдлийг экспорт хийж байна"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Өгөгдлийн сангийн мэдээллийг авч чадсангүй"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Экспорт хийж болох харилцагчид алга байна. Хэрэв та утсандаа харилцагчидтай байгаа бол зарим өгөгдөл нийлүүлэгчээс харилцагчдын мэдээллийг утаснаас экспорт хийхийг зөвшөөрөхгүй байж магадгүй."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard бичигч зохих ёсоор эхэлсэнгүй."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Экспорт хийж чадсангүй"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Харилцагчийн өгөгдлийг экспорт хийгээгүй.\nШалтгаан: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g>-г импорт хийж байна"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard өгөгдлийг уншиж чадсангүй"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard өгөгдөл уншихыг цуцлав"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g> -г импорт хийж дуусав"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g>-г импорт хийхийг цуцлав"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g>-г удахгүй импорт хийх болно."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Файлыг удахгүй импорт хийх болно."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard импорт хийх хүсэлтийг зөвшөөрсөнгүй. Дараа дахин оролдоно уу."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g>-г удахгүй экспорт хийх болно."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard экспорт хийх хүсэлтийг зөвшөөрсөнгүй. Дараа дахин оролдоно уу."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"харилцагч"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard-г дотоод түр санд кеш хийж байна. Удахгүй бодитоор импорт хийж эхлэх болно."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard-г импорт хийж чадсангүй."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC-р хүлээн авсан харилцагч"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Харилцагчдыг экспорт хийх үү?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Кеш хийж байна"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Импорт хийж байна <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Тохиргоо"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Харагдах харилцагчдыг хуваалцах"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Харилцагч импорт/экспорт"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Харилцагч импортлох"</string>
+ <string name="share_error" msgid="948429331673358107">"Энэ харилцагчийг хуваалцах боломжгүй."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Хайх"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Харуулах харилцагчид"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Харуулах харилцагчид"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Таалагддаг"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Харилцагч байхгүй."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Байнга харилцсаныг арилгах"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM карт сонгоно уу"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Импорт/экспорт"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Блоклосон дугаар"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g>-р"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="SOURCE">%2$s</xliff:g>-р"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Хайлтыг цэвэрлэх"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index 4f03f81..64e129e 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"डीफॉल्ट म्हणून सेट करा"</string>
<string name="clear_default" msgid="7193185801596678067">"डीफॉल्ट साफ करा"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"मजकूर कॉपी केला"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"आपले बदल टाकून देऊन संपादन सोडायचे?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"बदल टाकून द्यायचे?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"टाकून द्या"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"संपादन करणे सुरु ठेवा"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"रद्द करा"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"संपर्क शोधा"</string>
<string name="title_edit_group" msgid="8602752287270586734">"संपर्क काढा"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"विषयी"</string>
<string name="send_message" msgid="8938418965550543196">"संदेश पाठवा"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"वैयक्तिक प्रत तयार करीत आहे..."</string>
- <string name="yesterday" msgid="6840858548955018569">"काल"</string>
<string name="tomorrow" msgid="6241969467795308581">"उद्या"</string>
<string name="today" msgid="8041090779381781781">"आज"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"आज <xliff:g id="TIME_INTERVAL">%s</xliff:g> वाजता"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"संदेश"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"आपली सूची व्यवस्थापित करा"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"लेबल नुसार डुप्लिकेट आणि गट संपर्क साफ करा"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"मजकूर कॉपी केला"</string>
+ <string name="copy_text" msgid="3257145021583508761">"क्लिपबोर्डवर कॉपी करा"</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="8563753966926932052">"कॉल करा"</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="5745314124619636674">"फॅक्स वर कॉल करा"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"मजकूर"</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="3888842199855843152">"फॅक्सवर मजकूर पाठवा"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"वारंवार सपर्क साधलेले साफ करायचे?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"वारंवार सपर्क साधलेले साफ करीत आहे..."</string>
+ <string name="status_available" msgid="5586870015822828392">"उपलब्ध"</string>
+ <string name="status_away" msgid="1838861100379804730">"दूर आहे"</string>
+ <string name="status_busy" msgid="9147992455450257136">"व्यस्त"</string>
+ <string name="contactsList" msgid="8661624236494819731">"संपर्क"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"अन्य"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"निर्देशिका"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"सर्व संपर्क"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"शोधत आहे..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g> पेक्षा जास्त आढळले."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"कोणतेही संपर्क नाहीत"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> आढळला</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> आढळले</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> साठी द्रुत संपर्क"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(नाव नाही)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"वारंवार संपर्क केलेले"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"संपर्क पहा"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"फोन नंबरसह सर्व संपर्क"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"अद्यतने पहा"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"नाव"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"टोपणनाव"</string>
+ <string name="full_name" msgid="6602579550613988977">"नाव"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"ध्वन्यात्मक नाव"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"ध्वन्यात्मक मधले नाव"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"फोन"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"ईमेल"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"पत्ता"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"संस्था"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"नातेसंबंध"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"मजकूर संदेश"</string>
+ <string name="postal_address" msgid="8765560217149624536">"पत्ता"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"कंपनी"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"शीर्षक"</string>
+ <string name="label_notes" msgid="8337354953278341042">"टिपा"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"वेबसाइट"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"ईमेल"</string>
+ <string name="email_custom" msgid="7548003991586214105">"<xliff:g id="CUSTOM">%s</xliff:g> वर ईमेल करा"</string>
+ <string name="email" msgid="5668400997660065897">"ईमेल"</string>
+ <string name="postal_street" msgid="8133143961580058972">"मार्ग"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO बॉक्स"</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="map_home" msgid="1243547733423343982">"निवास पत्ता पहा"</string>
+ <string name="map_work" msgid="1360474076921878088">"कार्य पत्ता पहा"</string>
+ <string name="map_other" msgid="3817820803587012641">"पत्ता पहा"</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="description_minus_button" msgid="6908099247930477551">"हटवा"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"नाव फील्ड विस्तृत करा किंवा संकुचित करा"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"सर्व संपर्क"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"तारांकित"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"सानुकूलिकरण करा"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"संपर्क"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"इतर सर्व संपर्क"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"सर्व संपर्क"</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_warn_remove_ungrouped" msgid="8872290721676651414">"संकालन करा मधून \"<xliff:g id="GROUP">%s</xliff:g>\" हटविल्याने संकालन करा मधून कोणत्याही गटबद्ध न केलेल्या संपर्कांना देखील हटवेल."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"प्रदर्शन पर्याय जतन करत आहे…"</string>
+ <string name="menu_done" msgid="796017761764190697">"पूर्ण झाले"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"रद्द करा"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"सिमकार्डवरुन आयात करा"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> चे आयात रद्द करायचे?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> चे निर्यात रद्द करायचे?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard आयात/निर्यात रद्द करू शकल नाही"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"अज्ञात त्रुटी."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" उघडू शकलो नाही: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"निर्यातकर्ता प्रारंभ करू शकला नाही: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"कोणताही निर्यात करण्यायोग्य संपर्क नाही."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"निर्यात दरम्यान त्रुटी आलीt: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"आवश्यक फाईल नाव (\"<xliff:g id="FILENAME">%s</xliff:g>\") खूप मोठे आहे."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O त्रुटी"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"पुरेशी मेमरी नाही. फाईल कदाचित खूप मोठी असू शकते."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"अनपेक्षित कारणासाठी vCard विश्लेषण करू शकलो नाही."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"स्वरूपन समर्थित नाही."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"दिलेल्या vCard फाईल(यली) ची मेटा माहिती संकलित करू शकलो नाही."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"एक किंवा अधिक फायली आयात केल्या जाऊ शकत नाहीत(%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> निर्यात करणे समाप्त झाले."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> निर्यात करणे रद्द केले."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"संपर्क डेटा निर्यात करीत आहे"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"डेटाबेस माहिती मिळवू शकलो नाही."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"निर्यात करण्यायोग्य संपर्क नाहीत. आपल्या फोनवर संपर्क असल्यास, काही डेटा प्रदाते फोनवरून संपर्क निर्यात करण्यास कदाचित अनुमती देणार नाहीत."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard रचनाकाराने योग्यरित्या प्रारंभ केला नाही."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"निर्यात करू शकलो नाही"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"संपर्क डेटा निर्यात केला नाही.\nकारण: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> आयात करीत आहे"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard डेटा वाचू शकलो नाही"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard डेटा वाचणे रद्द केले"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g> आयात करणे समाप्त झाले"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> आयात करणे रद्द झाले"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> लवकरच आयात केली जाईल."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"फाईल लवकरच आयात केली जाईल."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard आयात विनंती नाकारली. नंतर पुन्हा प्रयत्न करा."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> लवकरच निर्यात केली जाईल."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard निर्यात विनंती नाकारली. नंतर पुन्हा प्रयत्न करा."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"संपर्क"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"स्थानिक तात्पुरत्या संचयनावर vCard(s) कॅशे करीत आहे. वास्तविक आयात लवकरच प्रारंभ होईल."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard आयात करू शकलो नाही."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC वर संपर्क प्राप्त केला"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"संपर्क निर्यात करायचे?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"कॅशे करीत आहे"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"आयात करत आहे <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"सेटिंग्ज"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"दृश्यमान संपर्क सामायिक करा"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"संपर्क आयात/निर्यात कराcts"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"संपर्क आयात करा"</string>
+ <string name="share_error" msgid="948429331673358107">"हा संपर्क सामायिक केला जाऊ शकत नाही."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"शोधा"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"प्रदर्शित करण्यासाठी संपर्क"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"प्रदर्शित करण्यासाठी संपर्क"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"आवडते"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"कोणतेही संपर्क नाहीत."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"वारंवारता साफ करा"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"सिम कार्ड निवडा"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"आयात/निर्यात"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"अवरोधित केलेले नंबर"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g> द्वारे"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="SOURCE">%2$s</xliff:g> द्वारे <xliff:g id="DATE">%1$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"शोध साफ करा"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index 50703d5..0c65eae 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Tetapkan lalai"</string>
<string name="clear_default" msgid="7193185801596678067">"Kosongkan lalai"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Teks disalin"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Buang perubahan anda dan keluar daripada pengeditan?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Buang perubahan?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Buang"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Teruskan mengedit"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Batal"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Cari dalam kenalan"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Alih keluar kenalan"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Mengenai"</string>
<string name="send_message" msgid="8938418965550543196">"Hantar mesej"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Membuat salinan peribadi..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Semalam"</string>
<string name="tomorrow" msgid="6241969467795308581">"Esok"</string>
<string name="today" msgid="8041090779381781781">"Hari ini"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Hari ini pada <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mesej"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Atur senarai anda"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Bersihkan pendua & himpunkan kenalan mengikut label"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Teks disalin"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Salin ke papan keratan"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Panggil <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Panggil nombor rumah"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Panggil nombor mudah alih"</string>
+ <string name="call_work" msgid="5328785911463744028">"Panggil tempat kerja"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Panggil faks tempat kerja"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Panggil faks rumah"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Panggil alat kelui"</string>
+ <string name="call_other" msgid="8563753966926932052">"Panggil"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Panggil nombor panggil balik"</string>
+ <string name="call_car" msgid="3280537320306436445">"Panggil kereta"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Panggil nombor utama syarikat"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Panggil ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Panggil nombor utama"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Panggil faks"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Panggil radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Panggil telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Panggil TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Panggil telefon mudah alih tempat kerja"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Panggil alat kelui tempat kerja"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Panggil <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Panggil MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"SMS ke <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"SMS ke rumah"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"SMS ke telefon mudah alih"</string>
+ <string name="sms_work" msgid="2269624156655267740">"SMS tempat kerja"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"SMS faks tempat kerja"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"SMS ke faks rumah"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"SMS alat kelui"</string>
+ <string name="sms_other" msgid="806127844607642331">"Teks"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"SMS ke nombor panggil balik"</string>
+ <string name="sms_car" msgid="7444227058437359641">"SMS ke kereta"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"SMS nombor utama syarikat"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"SMS ke ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"SMS ke nombor utama"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Faks teks"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"SMS ke radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"SMS ke teleks"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"SMS ke TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"SMS ke telefon mudah alih tempat kerja"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"SMS alat kelui tempat kerja"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"SMS ke <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"SMS kepada MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Padam bersih senarai kerap dihubungi?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Memadam bersih senarai kerap dihubungi..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Ada"</string>
+ <string name="status_away" msgid="1838861100379804730">"Tiada"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Sibuk"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kenalan"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Lain-lain"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Direktori"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Semua kenalan"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Mencari..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"lebih daripada <xliff:g id="COUNT">%d</xliff:g> ditemui."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Tiada kenalan"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ditemui</item>
+ <item quantity="one">1 ditemui</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Kenalan cepat untuk <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Tiada nama)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Kerap dihubungi"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Lihat kenalan"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Semua kenalan dengan nombor telefon"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Lihat kemas kini"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nama"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Nama panggilan"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nama"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Awalan nama"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Nama tengah"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Akhiran nama"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nama fonetik"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Nama tengah fonetik"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mel"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Alamat"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisasi"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Hubungan"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Mesej teks"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Alamat"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Syarikat"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Tajuk"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Nota"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Tapak web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"E-mel rumah"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-mel telefon mudah alih"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-mel tempat kerja"</string>
+ <string name="email_other" msgid="3454004077967657109">"E-mel"</string>
+ <string name="email_custom" msgid="7548003991586214105">"E-mel <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-mel"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Jalan"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Peti Surat"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Kawasan kejiranan"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Bandar"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Negeri"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Poskod"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Negara"</string>
+ <string name="map_home" msgid="1243547733423343982">"Lihat alamat rumah"</string>
+ <string name="map_work" msgid="1360474076921878088">"Lihat alamat tempat kerja"</string>
+ <string name="map_other" msgid="3817820803587012641">"Lihat alamat"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Lihat alamat <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Sembang menggunakan AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Sembang menggunakan Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Sembang menggunakan Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Sembang menggunakan Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Sembang menggunakan QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Sembang menggunakan Bual Google"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Sembang menggunakan ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Sembang menggunakan Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Sembang"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"padam"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Kembangkan atau runtuhkan medan nama"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Semua kenalan"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Dibintangkan"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Peribadikan"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kenalan"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Semua kenalan lain"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Semua kenalan"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Alih keluar kumpulan penyegerakan"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Tambah kumpulan segerak"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Lagi kumpulan..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Mengalih keluar \"<xliff:g id="GROUP">%s</xliff:g>\" daripada penyegerakan juga akan turut mengalih keluar sebarang kenalan tanpa kumpulan dari penyegerakan."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Menyimpan pilihan paparan..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Selesai"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Batal"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Import daripada kad SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Batalkan pengimportan <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Batalkan pengeksportan <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Tidak dapat membatalkan import/eksport vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Ralat tidak diketahui."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Tidak dapat membuka \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Tidak boleh memulakan pengeksport: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Tiada kenalan yang boleh dieksport."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Ralat berlaku semasa pengeksportan: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Nama fail yang diperlukan terlalu panjang (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Ralat I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Tidak cukup memori. Fail itu mungkin terlalu besar."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Tidak dapat menghurai vCard atas sebab-sebab yang tidak dijangka."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Format tidak disokong."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Tidak boleh mengumpul maklumat meta fail Vcard yang tertentu."</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Selesai mengeksport <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Pengeksportan <xliff:g id="FILENAME">%s</xliff:g> dibatalkan."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Mengeksport data kenalan"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Tidak boleh mendapatkan maklumat pangkalan data."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Tiada kenalan boleh dieksport. Jika anda mempunyai kenalan pada telefon anda, sesetengah pembekal data tidak boleh membenarkan kenalan dieksport dari telefon."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Komposer vCard tidak bermula dengan betul."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Tidak boleh mengeksport"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Data kenalan tidak dieksport.\nAlasan: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Mengimport <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Tidak dapat membaca data vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Membaca data vCard dibatalkan"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Selesai mengimport vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Pengimportan <xliff:g id="FILENAME">%s</xliff:g> dibatalkan"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> akan diimport sebentar lagi."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Fail akan diimport sebentar lagi."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Permintaan import vCard telah ditolak. Cuba lagi nanti."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> akan dieksport sebentar lagi."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Permintaan eksport vCard telah ditolak. Cuba lagi nanti."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kenalan"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Membuat cache vCard ke storan sementara tempatan. Pengimportan sebenar akan bermula tidak lama lagi."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Tidak dapat mengimport vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Knln melalui NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Eksport kenalan?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Mengcache..."</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Mengimport <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Tetapan"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Kongsi kenalan yang kelihatan"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Import/Eksport kenalan"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Import kenalan"</string>
+ <string name="share_error" msgid="948429331673358107">"Kenalan ini tidak boleh dikongsi."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Cari"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kenalan untuk dipaparkan"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kenalan untuk dipaparkan"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Kegemaran"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Tiada kenalan."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Padam bersih kerap dihubungi"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Pilih kad SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Import/eksport"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Nombor yang disekat"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"melalui <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> melalui <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Kosongkan carian"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index 53e6cbf..0d77f31 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"ပုံသေအဖြစ် သတ်မှတ်ခြင်း"</string>
<string name="clear_default" msgid="7193185801596678067">"မူရင်းများကို ရှင်းလင်းခြင်း"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"စာသားကူးယူပြီး"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"သင့်ပြောင်းလဲမှုများကို စွန့်ပစ်ပြီး တည်းဖြတ်မှုကို ရပ်မလား။"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"ပြင်ဆင်မှုများကို ဖယ်ပစ်မလား။"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"စွန့်ပစ်ရန်"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"ဆက်လက်တည်းဖြတ်ပါ"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"မလုပ်တော့"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"အဆက်အသွယ်များရှာပါ"</string>
<string name="title_edit_group" msgid="8602752287270586734">"အဆက်အသွယ်များ ဖယ်ရှားရန်"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"အကြောင်း"</string>
<string name="send_message" msgid="8938418965550543196">"စာတို ပို့ရန်"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"မိမိအတွက် ကိုယ်ပိုင်ကော်ပီ ပြုလုပ်နေစဉ်…"</string>
- <string name="yesterday" msgid="6840858548955018569">"မနေ့က"</string>
<string name="tomorrow" msgid="6241969467795308581">"နက်ဖြန်"</string>
<string name="today" msgid="8041090779381781781">"ယနေ့"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"ယနေ့ <xliff:g id="TIME_INTERVAL">%s</xliff:g> တွင်"</string>
@@ -342,4 +341,505 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"မက်ဆေ့ဂျ်များ"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"သင့်စာရင်းကို စနစ်တကျစီစဉ်ပါ"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"အဖွဲ့အဆက်အသွယ်များ & ထပ်နေသည်များကို အညွှန်းဖြင့် ရှင်းပါ"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"စာသားကူးယူပြီး"</string>
+ <string name="copy_text" msgid="3257145021583508761">"ခဏကူးယူထားပါ"</string>
+ <!-- no translation found for call_custom (7756571794763171802) -->
+ <skip />
+ <!-- no translation found for call_home (1990519474420545392) -->
+ <skip />
+ <!-- no translation found for call_mobile (7502236805487609178) -->
+ <skip />
+ <!-- no translation found for call_work (5328785911463744028) -->
+ <skip />
+ <!-- no translation found for call_fax_work (7467763592359059243) -->
+ <skip />
+ <!-- no translation found for call_fax_home (8342175628887571876) -->
+ <skip />
+ <!-- no translation found for call_pager (9003902812293983281) -->
+ <skip />
+ <!-- no translation found for call_other (8563753966926932052) -->
+ <skip />
+ <!-- no translation found for call_callback (1910165691349426858) -->
+ <skip />
+ <!-- no translation found for call_car (3280537320306436445) -->
+ <skip />
+ <!-- no translation found for call_company_main (6105120947138711257) -->
+ <skip />
+ <!-- no translation found for call_isdn (1541590690193403411) -->
+ <skip />
+ <!-- no translation found for call_main (6082900571803441339) -->
+ <skip />
+ <!-- no translation found for call_other_fax (5745314124619636674) -->
+ <skip />
+ <!-- no translation found for call_radio (8296755876398357063) -->
+ <skip />
+ <!-- no translation found for call_telex (2223170774548648114) -->
+ <skip />
+ <!-- no translation found for call_tty_tdd (8951266948204379604) -->
+ <skip />
+ <!-- no translation found for call_work_mobile (8707874281430105394) -->
+ <skip />
+ <!-- no translation found for call_work_pager (3419348514157949008) -->
+ <skip />
+ <!-- no translation found for call_assistant (2141641383068514308) -->
+ <skip />
+ <!-- no translation found for call_mms (6274041545876221437) -->
+ <skip />
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <!-- no translation found for sms_custom (5932736853732191825) -->
+ <skip />
+ <!-- no translation found for sms_home (7524332261493162995) -->
+ <skip />
+ <!-- no translation found for sms_mobile (5200107250451030769) -->
+ <skip />
+ <!-- no translation found for sms_work (2269624156655267740) -->
+ <skip />
+ <!-- no translation found for sms_fax_work (8028189067816907075) -->
+ <skip />
+ <!-- no translation found for sms_fax_home (9204042076306809634) -->
+ <skip />
+ <!-- no translation found for sms_pager (7730404569637015192) -->
+ <skip />
+ <!-- no translation found for sms_other (806127844607642331) -->
+ <skip />
+ <!-- no translation found for sms_callback (5004824430094288752) -->
+ <skip />
+ <!-- no translation found for sms_car (7444227058437359641) -->
+ <skip />
+ <!-- no translation found for sms_company_main (118970873419678087) -->
+ <skip />
+ <!-- no translation found for sms_isdn (8153785037515047845) -->
+ <skip />
+ <!-- no translation found for sms_main (8621625784504541679) -->
+ <skip />
+ <!-- no translation found for sms_other_fax (3888842199855843152) -->
+ <skip />
+ <!-- no translation found for sms_radio (3329166673433967820) -->
+ <skip />
+ <!-- no translation found for sms_telex (9034802430065267848) -->
+ <skip />
+ <!-- no translation found for sms_tty_tdd (6782284969132531532) -->
+ <skip />
+ <!-- no translation found for sms_work_mobile (2459939960512702560) -->
+ <skip />
+ <!-- no translation found for sms_work_pager (5566924423316960597) -->
+ <skip />
+ <!-- no translation found for sms_assistant (2773424339923116234) -->
+ <skip />
+ <!-- no translation found for sms_mms (4069352461380762677) -->
+ <skip />
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation_title (766292372438450432) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <!-- no translation found for clearFrequentsProgress_title (5157001637482794212) -->
+ <skip />
+ <!-- no translation found for status_available (5586870015822828392) -->
+ <skip />
+ <!-- no translation found for status_away (1838861100379804730) -->
+ <skip />
+ <!-- no translation found for status_busy (9147992455450257136) -->
+ <skip />
+ <string name="contactsList" msgid="8661624236494819731">"အဆက်အသွယ်များ"</string>
+ <!-- no translation found for local_invisible_directory (6046691709127661065) -->
+ <skip />
+ <!-- no translation found for directory_search_label (1887759056597975053) -->
+ <skip />
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <!-- no translation found for local_search_label (2551177578246113614) -->
+ <skip />
+ <string name="search_results_searching" msgid="3984833028938569930">"ရှာဖွေနေသည်…"</string>
+ <!-- no translation found for foundTooManyContacts (5163335650920020220) -->
+ <skip />
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"အဆက်အသွယ်များမရှိ"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ခုတွေ့ရှိသည်</item>
+ <item quantity="one">1ခု တွေ့ရှိသည်</item>
+ </plurals>
+ <!-- no translation found for description_quick_contact_for (6737516415168327789) -->
+ <skip />
+ <!-- no translation found for missing_name (8745511583852904385) -->
+ <skip />
+ <!-- no translation found for favoritesFrequentContacted (6184232487472425690) -->
+ <skip />
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"အဆက်အသွယ်အား ကြည့်ရန်"</string>
+ <!-- no translation found for list_filter_phones (735313795643493365) -->
+ <skip />
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <!-- no translation found for view_updates_from_group (1782685984905600034) -->
+ <skip />
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <!-- no translation found for nameLabelsGroup (2034640839640477827) -->
+ <skip />
+ <!-- no translation found for nicknameLabelsGroup (2891682101053358010) -->
+ <skip />
+ <!-- no translation found for full_name (6602579550613988977) -->
+ <skip />
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <!-- no translation found for name_prefix (59756378548779822) -->
+ <skip />
+ <!-- no translation found for name_middle (8467433655992690326) -->
+ <skip />
+ <!-- no translation found for name_suffix (3855278445375651441) -->
+ <skip />
+ <!-- no translation found for name_phonetic (4259595234312430484) -->
+ <skip />
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <!-- no translation found for name_phonetic_middle (8643721493320405200) -->
+ <skip />
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <!-- no translation found for phoneLabelsGroup (6468091477851199285) -->
+ <skip />
+ <!-- no translation found for emailLabelsGroup (8389931313045344406) -->
+ <skip />
+ <!-- no translation found for postalLabelsGroup (3487738141112589324) -->
+ <skip />
+ <!-- no translation found for imLabelsGroup (3898238486262614027) -->
+ <skip />
+ <!-- no translation found for organizationLabelsGroup (2478611760751832035) -->
+ <skip />
+ <!-- no translation found for relationLabelsGroup (1854373894284572781) -->
+ <skip />
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <!-- no translation found for sms (1756857139634224222) -->
+ <skip />
+ <!-- no translation found for postal_address (8765560217149624536) -->
+ <skip />
+ <!-- no translation found for ghostData_company (5414421120553765775) -->
+ <skip />
+ <!-- no translation found for ghostData_title (7496735200318496110) -->
+ <skip />
+ <!-- no translation found for label_notes (8337354953278341042) -->
+ <skip />
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <!-- no translation found for websiteLabelsGroup (4202998982804009261) -->
+ <skip />
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <!-- no translation found for email_home (8573740658148184279) -->
+ <skip />
+ <!-- no translation found for email_mobile (2042889209787989814) -->
+ <skip />
+ <!-- no translation found for email_work (2807430017302722689) -->
+ <skip />
+ <!-- no translation found for email_other (3454004077967657109) -->
+ <skip />
+ <!-- no translation found for email_custom (7548003991586214105) -->
+ <skip />
+ <!-- no translation found for email (5668400997660065897) -->
+ <skip />
+ <!-- no translation found for postal_street (8133143961580058972) -->
+ <skip />
+ <!-- no translation found for postal_pobox (4431938829180269821) -->
+ <skip />
+ <!-- no translation found for postal_neighborhood (1450783874558956739) -->
+ <skip />
+ <!-- no translation found for postal_city (6597491300084895548) -->
+ <skip />
+ <!-- no translation found for postal_region (6045263193478437672) -->
+ <skip />
+ <!-- no translation found for postal_postcode (572136414136673751) -->
+ <skip />
+ <!-- no translation found for postal_country (7638264508416368690) -->
+ <skip />
+ <!-- no translation found for map_home (1243547733423343982) -->
+ <skip />
+ <!-- no translation found for map_work (1360474076921878088) -->
+ <skip />
+ <!-- no translation found for map_other (3817820803587012641) -->
+ <skip />
+ <!-- no translation found for map_custom (6184363799976265281) -->
+ <skip />
+ <!-- no translation found for chat_aim (2588492205291249142) -->
+ <skip />
+ <!-- no translation found for chat_msn (8041633440091073484) -->
+ <skip />
+ <!-- no translation found for chat_yahoo (6629211142719943666) -->
+ <skip />
+ <!-- no translation found for chat_skype (1210045020427480566) -->
+ <skip />
+ <!-- no translation found for chat_qq (4294637812847719693) -->
+ <skip />
+ <!-- no translation found for chat_gtalk (981575737258117697) -->
+ <skip />
+ <!-- no translation found for chat_icq (8438405386153745775) -->
+ <skip />
+ <!-- no translation found for chat_jabber (7561444230307829609) -->
+ <skip />
+ <!-- no translation found for chat (9025361898797412245) -->
+ <skip />
+ <!-- no translation found for description_minus_button (6908099247930477551) -->
+ <skip />
+ <!-- no translation found for expand_collapse_name_fields_description (8682630859539604311) -->
+ <skip />
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <!-- no translation found for list_filter_all_accounts (8908683398914322369) -->
+ <skip />
+ <!-- no translation found for list_filter_all_starred (5031734941601931356) -->
+ <skip />
+ <!-- no translation found for list_filter_customize (4789963356004169321) -->
+ <skip />
+ <!-- no translation found for list_filter_single (5871400283515893087) -->
+ <skip />
+ <!-- no translation found for display_ungrouped (6885954210243119591) -->
+ <skip />
+ <!-- no translation found for display_all_contacts (2031647544742889505) -->
+ <skip />
+ <!-- no translation found for menu_sync_remove (3266725887008450161) -->
+ <skip />
+ <!-- no translation found for dialog_sync_add (8267045393119375803) -->
+ <skip />
+ <!-- no translation found for display_more_groups (2682547080423434170) -->
+ <skip />
+ <!-- no translation found for display_warn_remove_ungrouped (8872290721676651414) -->
+ <skip />
+ <!-- no translation found for savingDisplayGroups (2133152192716475939) -->
+ <skip />
+ <!-- no translation found for menu_done (796017761764190697) -->
+ <skip />
+ <!-- no translation found for menu_doNotSave (58593876893538465) -->
+ <skip />
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <!-- no translation found for import_from_sim (3859272228033941659) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <!-- no translation found for cancel_import_confirmation_message (3929951040347726757) -->
+ <skip />
+ <!-- no translation found for cancel_export_confirmation_message (1995462401949262638) -->
+ <skip />
+ <!-- no translation found for cancel_vcard_import_or_export_failed (6139900383366166706) -->
+ <skip />
+ <!-- no translation found for fail_reason_unknown (1714092345030570863) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_open_file (2067725459821997463) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_initialize_exporter (707260459259688510) -->
+ <skip />
+ <!-- no translation found for fail_reason_no_exportable_contact (8728506011371262065) -->
+ <skip />
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <!-- no translation found for fail_reason_error_occurred_during_export (3018855323913649063) -->
+ <skip />
+ <!-- no translation found for fail_reason_too_long_filename (3393764245254738333) -->
+ <skip />
+ <!-- no translation found for fail_reason_io_error (6748358842976073255) -->
+ <skip />
+ <!-- no translation found for fail_reason_low_memory_during_import (875222757734882898) -->
+ <skip />
+ <!-- no translation found for fail_reason_vcard_parse_error (888263542360355784) -->
+ <skip />
+ <!-- no translation found for fail_reason_not_supported (8219562769267148825) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_collect_vcard_meta_info (6427931733267328564) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title (4767045779458185251) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_canceled_title (2652222370493306887) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <!-- no translation found for composer_failed_to_get_database_infomation (1765944280846236723) -->
+ <skip />
+ <!-- no translation found for composer_has_no_exportable_contact (3296493229040294335) -->
+ <skip />
+ <!-- no translation found for composer_not_initialized (2321648986367005254) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_title (4892358112409576342) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_message (4938527850142003141) -->
+ <skip />
+ <!-- no translation found for importing_vcard_description (4245275224298571351) -->
+ <skip />
+ <!-- no translation found for reading_vcard_failed_title (4251647443358422855) -->
+ <skip />
+ <!-- no translation found for reading_vcard_canceled_title (1925216585981542019) -->
+ <skip />
+ <!-- no translation found for importing_vcard_finished_title (3341541727268747967) -->
+ <skip />
+ <!-- no translation found for importing_vcard_canceled_title (2147475978165599336) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message (2804911199145873396) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message_with_default_name (1022969530654129470) -->
+ <skip />
+ <!-- no translation found for vcard_import_request_rejected_message (2890471184508516011) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message (2210241345252081463) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <!-- no translation found for vcard_export_request_rejected_message (2844874826431327531) -->
+ <skip />
+ <!-- no translation found for vcard_unknown_filename (7171709890959915954) -->
+ <skip />
+ <!-- no translation found for caching_vcard_message (4926308675041506756) -->
+ <skip />
+ <!-- no translation found for vcard_import_failed (5223531255894842406) -->
+ <skip />
+ <!-- no translation found for nfc_vcard_file_name (2823095213265993609) -->
+ <skip />
+ <!-- no translation found for confirm_export_title (6834385377255286349) -->
+ <skip />
+ <!-- no translation found for caching_vcard_title (1226272312940516605) -->
+ <skip />
+ <!-- no translation found for progress_notifier_message (2311011466908220528) -->
+ <skip />
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"အပြင်အဆင်များ"</string>
+ <!-- no translation found for share_visible_contacts (890150378880783797) -->
+ <skip />
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <!-- no translation found for dialog_import_export (4360648034889921624) -->
+ <skip />
+ <!-- no translation found for dialog_import (2431698729761448759) -->
+ <skip />
+ <!-- no translation found for share_error (948429331673358107) -->
+ <skip />
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <!-- no translation found for menu_search (9147752853603483719) -->
+ <skip />
+ <!-- no translation found for menu_contacts_filter (2165153460860262501) -->
+ <skip />
+ <!-- no translation found for activity_title_contacts_filter (8275542497615516969) -->
+ <skip />
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <!-- no translation found for contactsFavoritesLabel (8417039765586853670) -->
+ <skip />
+ <!-- no translation found for listTotalAllContactsZero (5513001821794568211) -->
+ <skip />
+ <!-- no translation found for menu_clear_frequents (7688250191932838833) -->
+ <skip />
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM ကဒ်ကို ရွေးရန်"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <!-- no translation found for menu_import_export (26217871113229507) -->
+ <skip />
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"ပိတ်ဆို့ထားသည့် နံပါတ်များ"</string>
+ <!-- no translation found for contact_status_update_attribution (752179367353018597) -->
+ <skip />
+ <!-- no translation found for contact_status_update_attribution_with_date (7358045508107825068) -->
+ <skip />
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"ရှာဖွေမှုကို ရှင်းပါ"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 71f2cdf..8ef3a9b 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Angi som standard"</string>
<string name="clear_default" msgid="7193185801596678067">"Fjern som standard"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Tekst kopiert"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Vil du forkaste endringene og avslutte endringsmodusen?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Vil du forkaste endringene?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Forkast"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Fortsett å endre"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Avbryt"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Søk etter kontakter"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Fjern kontakter"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Info"</string>
<string name="send_message" msgid="8938418965550543196">"Send melding"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Oppretter personlig kopi …"</string>
- <string name="yesterday" msgid="6840858548955018569">"I går"</string>
<string name="tomorrow" msgid="6241969467795308581">"I morgen"</string>
<string name="today" msgid="8041090779381781781">"I dag"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"I dag kl. <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Meldinger"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organiser listen din"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Rydd opp i duplikater og & gruppér kontaktene dine etter etiketter"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Tekst kopiert"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopier til utklippstavlen"</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="8563753966926932052">"Ring"</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="5745314124619636674">"Ring til faksnummer"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Send tekstmelding"</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="3888842199855843152">"Send tekstmelding til faksnummer"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Fjerne ofte kontaktede personer?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Fjerner ofte kontaktede personer"</string>
+ <string name="status_available" msgid="5586870015822828392">"Tilgjengelig"</string>
+ <string name="status_away" msgid="1838861100379804730">"Borte"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Opptatt"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontakter"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Andre"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Katalog"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Alle kontakter"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Søker …"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Fant over <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Ingen kontakter"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> er funnet</item>
+ <item quantity="one">1 er funnet</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Hurtigkontakt for <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Uten navn)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Ofte kontaktet"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Se kontakt"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Alle kontakter med telefonnumre"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Se oppdateringer"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Navn"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Kallenavn"</string>
+ <string name="full_name" msgid="6602579550613988977">"Navn"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Fonetisk navn"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetisk mellomnavn"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-post"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adresse"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Lynmeldinger"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisering"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relasjon"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Tekstmelding"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adresse"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Firma"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Tittel"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notater"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Nettsted"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"E-post"</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="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="map_home" msgid="1243547733423343982">"Vis privat adresse"</string>
+ <string name="map_work" msgid="1360474076921878088">"Vis jobbadresse"</string>
+ <string name="map_other" msgid="3817820803587012641">"Vis adresse"</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="description_minus_button" msgid="6908099247930477551">"slett"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Vis eller skjul navnefelt"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Alle kontakter"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Stjernemerket"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Tilpass"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontakt"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Alle andre kontakter"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Alle kontaktene"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Hvis du fjerner «<xliff:g id="GROUP">%s</xliff:g>» fra synkroniseringen, fjernes også alle ugrupperte kontakter fra synkroniseringen."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Lagrer viste grupper…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Lagre"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Avbryt"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importér fra SIM-kort"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Vil du avbryte importen av <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Vil du avbryte eksporten av <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Kunne ikke kansellere imp./eksp. av vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Ukjent feil."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Kan ikke åpne «<xliff:g id="FILE_NAME">%s</xliff:g>»: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Kunne ikke starte eksporteringen: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Du har ikke noen kontakt som kan eksporteres."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Det oppsto en feil under eksporteringen: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Det obligatoriske filnavnet er for langt (<xliff:g id="FILENAME">%s</xliff:g>)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Inn-/ut-feil"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Ikke nok minne. Det er mulig at filen er for stor."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Kan ikke analysere vCard av uventet årsak."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Formatet støttes ikke."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Kunne ikke hente metainformasjon for aktuell(e) vCard-fil(er)."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"En eller flere filer kan ikke importeres (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Eksportering av <xliff:g id="FILENAME">%s</xliff:g> er fullført."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Eksportering av <xliff:g id="FILENAME">%s</xliff:g> ble avbrutt."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Eksporterer kontaktdata"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Kunne ikke hente databaseinformasjon."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Du har ingen kontakter som kan eksporteres. Hvis du har kontakter på telefonen, kan det hende at dataleverandøren din ikke tillater at kontaktene eksporteres fra telefonen."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard-oppretteren startet ikke som den skulle."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Eksport mislyktes"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Kontaktdataene ble ikke eksportert.\nGrunn: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importerer <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Kunne ikke lese vCard-data"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Lesing av vCard-data avbrutt"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Import av vCard-filen <xliff:g id="FILENAME">%s</xliff:g> er fullført"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importeringen av <xliff:g id="FILENAME">%s</xliff:g> ble avbrutt"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> vil importeres snart."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Filen importeres snart."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Forespørselen om vCard-import ble avvist. Prøv på nytt senere."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> vil eksporteres snart."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Forespørselen om eksport av vCard ble avvist. Prøv på nytt senere."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontakt"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Bufrer vCard for import til lokal, midlertidig lagring. Selve importen starter snart."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Kunne ikke importere vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontakt mottatt per NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Eksp. kontaktene?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Bufrer"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importerer <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Innstillinger"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Del synlige kontakter"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Imp./eksp. kontakter"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importer kontakter"</string>
+ <string name="share_error" msgid="948429331673358107">"Denne kontakten kan ikke deles."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Søk"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kontakter i visning"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kontakter i visning"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritter"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Ingen kontakter."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Fjern ofte kontaktede personer"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Velg SIM-kort"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importér/eksportér"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blokkerte telefonnumre"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Slett søk"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index d435073..a0afa01 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"पूर्वनिर्धारित मिलाउनुहोस्"</string>
<string name="clear_default" msgid="7193185801596678067">"पूर्वनिर्धारित हटाउनुहोस्"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"पाठको प्रतिलिपि गरियो"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"तपाईंका परिवर्तनहरू खारेज गरी सम्पादनलाई छाड्ने हो?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"परिवर्तनहरू खारेज गर्ने हो?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"खारेज गर्नुहोस्"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"सम्पादन गरिरहनुहोस्"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"रद्द गर्नुहोस्"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"सम्पर्कहरू खोज्नुहोस्"</string>
<string name="title_edit_group" msgid="8602752287270586734">"सम्पर्कहरू हटाउनुहोस्"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"बारेमा"</string>
<string name="send_message" msgid="8938418965550543196">"सन्देश पठाउनुहोस्"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"एउटा व्यक्तिगत प्रतिलिपि बनाउँदै..."</string>
- <string name="yesterday" msgid="6840858548955018569">"हिजो"</string>
<string name="tomorrow" msgid="6241969467795308581">"भोलि"</string>
<string name="today" msgid="8041090779381781781">"आज"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"<xliff:g id="TIME_INTERVAL">%s</xliff:g>मा आज"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"सन्देशहरू"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"आफ्नो सूची संगठित गर्नुहोस्"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"प्रतिलिपिहरू हटाउनुहोस् & लेबलका आधारमा सम्पर्कहरूको समूह बनाउनुहोस्"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"पाठको प्रतिलिपि गरियो"</string>
+ <string name="copy_text" msgid="3257145021583508761">"क्लिपबोर्डमा प्रतिलिपि गर्नुहोस्"</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="8563753966926932052">"कल गर्नुहोस्"</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="5745314124619636674">"फ्याक्स कल गर्नुहोस्"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"पाठ"</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="3888842199855843152">"पाठ फ्याक्स"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"प्रायः सम्पर्क गरिएकाहरूलाई हटाउने हो?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"प्रायः सम्पर्क गरिएकाहरूलाई हटाउँदै...."</string>
+ <string name="status_available" msgid="5586870015822828392">"उपलब्ध"</string>
+ <string name="status_away" msgid="1838861100379804730">"टाढा"</string>
+ <string name="status_busy" msgid="9147992455450257136">"व्यस्त"</string>
+ <string name="contactsList" msgid="8661624236494819731">"सम्पर्क"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"अन्य"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"निर्देशिका"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"सबै सम्पर्कहरू"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"खोजी कार्य गर्दै..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g> भन्दा अधिक पाइयो।"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"कुनै सम्पर्कहरू छैनन्।"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> फेला पर्यो</item>
+ <item quantity="one">1 फेला पर्यो</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g>का लागि छिटो सम्पर्क"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(नाम छैन)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"लगातार सम्पर्क गरिएको"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"सम्पर्क हेर्नुहोस्"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"फोन नम्बर भएका सबै सम्पर्कहरू"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"अद्यावधिकहरू हेर्नुहोस्"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"नाम"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"उपनाम"</string>
+ <string name="full_name" msgid="6602579550613988977">"नाम"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"फोनेटिक नाम"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"बिच फोनेटिक नाम"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"फोन"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"इमेल"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"ठेगाना"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"संगठन"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"सम्बन्ध"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"पाठ सन्देश"</string>
+ <string name="postal_address" msgid="8765560217149624536">"ठेगाना"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"कम्पनी"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"शीर्षक"</string>
+ <string name="label_notes" msgid="8337354953278341042">"टिप्पणीहरू"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"वेबसाइट"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"इमेल"</string>
+ <string name="email_custom" msgid="7548003991586214105">"इमेल <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"इमेल"</string>
+ <string name="postal_street" msgid="8133143961580058972">"सडक"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO Box:"</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">"ZIP कोड"</string>
+ <string name="postal_country" msgid="7638264508416368690">"देश"</string>
+ <string name="map_home" msgid="1243547733423343982">"घरको ठेगाना हेर्नुहोस्"</string>
+ <string name="map_work" msgid="1360474076921878088">"काम गर्ने ठाउँको ठेगाना हेर्नुहोस्"</string>
+ <string name="map_other" msgid="3817820803587012641">"ठेगाना हेर्नुहोस्"</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">"विन्डोज लाइभ प्रयोग गरेर च्याट गर्नुहोस्"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"याहुको प्रयोग गरेर च्याट गर्नुहोस्"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"स्काइपको प्रयोग गरेर च्याट गर्नुहोस्"</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">"ज्याबरको प्रयोग गरेर च्याट गर्नुहोस्"</string>
+ <string name="chat" msgid="9025361898797412245">"कुराकानी"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"मेटाउनुहोस्"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"मिति"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"सबै सम्पर्कहरू"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"ताराङ्कित"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"व्यक्तिगत् बनाउनुहोस्"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"ठेगाना"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"अन्य सबै सम्पर्कहरू"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"सबै सम्पर्कहरू"</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_warn_remove_ungrouped" msgid="8872290721676651414">"\" <xliff:g id="GROUP">%s</xliff:g> \" लाई सिङ्कबाट हटाउनाले समूहमा नरहेका सम्पर्कहरूलाई पनि हटाउने छ।"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"प्रदर्शन विकल्पहरू बचत गर्दै ..."</string>
+ <string name="menu_done" msgid="796017761764190697">"भयो"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"रद्द गर्नुहोस्"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM कार्डबाट आयात गर्नुहोस्"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g>को आयात रद्द गर्ने?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g>को निर्यात रद्द गर्ने?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard आयात/निर्यात रद्द गर्न सकिएन"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"अज्ञात त्रुटि।"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"खोल्न सकेन \" <xliff:g id="FILE_NAME">%s</xliff:g> : \" <xliff:g id="EXACT_REASON">%s</xliff:g> ।"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"निर्यातकर्ता: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\" सुरु गर्न सकेन्।"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"कुनै निर्यात गर्न मिल्ने सम्पर्क छैन।"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"\"<xliff:g id="EXACT_REASON">%s</xliff:g>\": निर्यात गर्ने क्रममा त्रुटि भयो।"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"आवश्यक फाइलनाम ज्यादै लामो छ (\" <xliff:g id="FILENAME">%s</xliff:g> \")।"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O त्रुटि"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"मेमोरी प्रयाप्त छैन। फाइल धेरै ठूलो हुन सक्छ।"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"एउटा अप्रत्याशित कारणले vCard पार्स गर्न सकेन।"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"ढाँचा समर्थित छैन।"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"दिइएको vCard फाइल(हरू)को अधिजानकारी जम्मा गर्न सकेन।"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"एक या धेरै फाइलहरू आयात (%s) गर्न सकिएन।"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> निर्यात कार्य सकियो।"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"निर्यात <xliff:g id="FILENAME">%s</xliff:g> रद्द गरियो।"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"सम्पर्क डेटा निर्यात हुँदै"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"डेटाबेस जानकारी प्राप्त गर्न सकेन।"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"कुनै पनि निर्यात गर्ने मिल्ने सम्पर्क छैनन्। यदि तपाईँसँग फोनमा सच्चिकै सम्पर्कहरू छन् भने केही डेटा प्रदायकहरूबाट सम्पुर्ण सम्पर्कहरू निर्यात गर्न मनाही गरिएको हुन सक्छ।"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard कम्पोजर राम्ररी सुर भएन।"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"निर्यात गर्न सकेन"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"सम्पर्क डेटा निर्यात गर्न सकिएन \n कारण: \" <xliff:g id="FAIL_REASON">%s</xliff:g> \""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g>आयात गर्दै"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"VCard डेटा पढ्न सकेन"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard डेटा पढ्न रद्द गरियो"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g> आयात कार्य सकियो"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g>आयात रद्द गरियो"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> शीघ्र आयात गरिने छ।"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"फाइल छिट्टै आयात गरिने छ।"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard निर्यात अनुरोध अस्वीकार गरिएको छ । कृपया पछि पर्यास गर्नुहोस्"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> शीघ्र निर्यात गरिने छ।"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard निर्यात अनुरोध अस्वीकार गरियो। पछि पुनःप्रयास गर्नुहोस्।"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"सम्पर्क"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard(s) लाई स्थानीय अस्थायी भण्डारणमा क्यास गर्दै। वास्तविक आयात छिट्टै सुरु हुन्छ।"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"VCard आयात गर्न सकेन।"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFCमा सम्पर्क प्राप्त गरियो"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"सम्पर्कहरू निर्यात गर्ने हो?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"केसिङ"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"आयात गर्दै <xliff:g id="CURRENT_NUMBER">%s</xliff:g> / <xliff:g id="TOTAL_NUMBER">%s</xliff:g> : <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"सेटिङहरू"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"देखिने सम्पर्कहरु साझेदारी गर्नुहोस्"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"आयात/निर्यात सम्पर्कहरू"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"सम्पर्कहरू आयात गर्नुहोस्"</string>
+ <string name="share_error" msgid="948429331673358107">"यो सम्पर्क साझेदारी गर्न मिल्दैन।"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"खोज्नुहोस्"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"प्रदर्शन गर्नका लागि सम्पर्क"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"प्रदर्शन गर्नका लागि सम्पर्क"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"मनपर्ने"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"कुनै सम्पर्क छैन।"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"बारम्बार गरिएको क्लियर गर्नुहोस्"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"सिम कार्ड चयन गर्नुहोस्"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"आयात/निर्यात"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"रोकिएका नम्बरहरू"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g>मार्फत"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> मार्फत <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"खोजी सफा गर्नुहोस्"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index ee1e7a2..f75ad91 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Standaard instellen"</string>
<string name="clear_default" msgid="7193185801596678067">"Standaardwaarden wissen"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Tekst gekopieerd"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Je wijzigingen weggooien en ophouden met bewerken?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Wijzigingen annuleren?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Weggooien"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Blijven bewerken"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Annuleren"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Contacten zoeken"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Contacten verwijderen"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Over"</string>
<string name="send_message" msgid="8938418965550543196">"Bericht verzenden"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Een persoonlijke kopie maken..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Gisteren"</string>
<string name="tomorrow" msgid="6241969467795308581">"Morgen"</string>
<string name="today" msgid="8041090779381781781">"Vandaag"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Vandaag om <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Berichten"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Je lijst ordenen"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Dubbele contacten opruimen en contacten groeperen op label"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Tekst gekopieerd"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopiëren naar klembord"</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="8563753966926932052">"Bellen"</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="5745314124619636674">"Fax bellen"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Sms\'en"</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="3888842199855843152">"Fax sms\'en"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Lijst met regelmatige contacten wissen?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Regelmatige contacten wissen..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Beschikbaar"</string>
+ <string name="status_away" msgid="1838861100379804730">"Afwezig"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Bezet"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contacten"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Overig"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Directory"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Alle contacten"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Zoeken..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Meer dan <xliff:g id="COUNT">%d</xliff:g> gevonden."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Geen contacten"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> gevonden</item>
+ <item quantity="one">1 gevonden</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Snelcontact voor <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Geen naam)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Regelmatig contact"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Contact weergeven"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Alle contacten met telefoonnummers"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Updates bekijken"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Naam"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Bijnaam"</string>
+ <string name="full_name" msgid="6602579550613988977">"Naam"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Fonetische naam"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetische tweede voornaam"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefoon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mailadres"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adres"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Chat"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisatie"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relatie"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Sms"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adres"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Bedrijf"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titel"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Opmerkingen"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"E-mail"</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="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="map_home" msgid="1243547733423343982">"Thuisadres weergeven"</string>
+ <string name="map_work" msgid="1360474076921878088">"Werkadres weergeven"</string>
+ <string name="map_other" msgid="3817820803587012641">"Adres 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="description_minus_button" msgid="6908099247930477551">"verwijderen"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Naamvelden uitvouwen of samenvouwen"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Alle contacten"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Met ster"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Aanpassen"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contacten"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Alle andere contacten"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Alle contacten"</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>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Als je \'<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="savingDisplayGroups" msgid="2133152192716475939">"Weergaveopties opslaan..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Gereed"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Annuleren"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importeren van SIM-kaart"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Import van <xliff:g id="FILENAME">%s</xliff:g> annuleren?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Export van <xliff:g id="FILENAME">%s</xliff:g> annuleren?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Kan vCard-import/export niet annuleren"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Onbekende fout."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Kan \'<xliff:g id="FILE_NAME">%s</xliff:g>\' niet openen: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Kan het exportprogramma niet starten: \'<xliff:g id="EXACT_REASON">%s</xliff:g>\'."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Er is geen contact dat kan worden geëxporteerd."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Er is een fout opgetreden tijdens het exporteren: \'<xliff:g id="EXACT_REASON">%s</xliff:g>\'."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Vereiste bestandsnaam is te lang (\'<xliff:g id="FILENAME">%s</xliff:g>\')."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O-fout"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Onvoldoende geheugen. Het bestand is mogelijk te groot."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Kan vCard om onverwachte reden niet parseren."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"De indeling wordt niet ondersteund."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Kan metagegevens niet verzamelen uit vCard-bestand(en)."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Kan een of meer bestanden niet importeren (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Exporteren van <xliff:g id="FILENAME">%s</xliff:g> voltooid."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exporteren van <xliff:g id="FILENAME">%s</xliff:g> geannuleerd."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Contactgegevens exporteren"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Kan databasegegevens niet ophalen."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Er zijn geen exporteerbare contacten. Als je wel contacten op je telefoon hebt opgeslagen, staat je gegevensprovider het exporteren van contacten van de telefoon mogelijk niet toe."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"De vCard-editor is niet correct gestart."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Kan niet exporteren"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"De contactgegevens zijn niet geëxporteerd.\nReden: \'<xliff:g id="FAIL_REASON">%s</xliff:g>\'"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> importeren"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Kan vCard-gegevens niet lezen"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Lezen van vCard-gegevens geannuleerd"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Importeren van vCard <xliff:g id="FILENAME">%s</xliff:g> voltooid"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importeren van <xliff:g id="FILENAME">%s</xliff:g> geannuleerd"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> wordt binnenkort geïmporteerd."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Het bestand wordt binnenkort geïmporteerd."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Verzoek voor vCard-import is geweigerd. Probeer het later opnieuw."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> wordt binnenkort geëxporteerd."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Verzoek voor vCard-export is geweigerd. Probeer het later opnieuw."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contact"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Bezig met opslaan van vCard(s) in de lokale tijdelijke opslag. Het daadwerkelijke importeren begint binnenkort."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Kan vCard niet importeren."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contact via NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Contacten export.?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"In cachegeheugen opslaan"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importeren <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Instellingen"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Zichtbare contacten delen"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Contacten importeren/exporteren"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Contacten importeren"</string>
+ <string name="share_error" msgid="948429331673358107">"Dit contact kan niet worden gedeeld."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Zoeken"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Zichtbare contacten"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Zichtbare contacten"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriet"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Geen contacten"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Regelmatige contacten wissen"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Simkaart selecteren"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importeren/exporteren"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Geblokkeerde nummers"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Zoekopdracht wissen"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
index 766187a..f7f7ef0 100644
--- a/res/values-pa-rIN/strings.xml
+++ b/res/values-pa-rIN/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"ਡਿਫੌਲਟ ਸੈਟ ਕਰੋ"</string>
<string name="clear_default" msgid="7193185801596678067">"ਡਿਫੌਲਟ ਹਟਾਓ"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"ਟੈਕਸਟ ਕਾਪੀ ਕੀਤਾ"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"ਕੀ ਆਪਣੀਆਂ ਤਬਦੀਲੀਆਂ ਨੂੰ ਛੱਡਣਾ ਅਤੇ ਸੰਪਾਦਨ ਨੂੰ ਰੱਦ ਕਰਨਾ ਹੈ?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"ਕੀ ਤਬਦੀਲੀਆਂ ਖਾਰਜ ਕਰਨੀਆਂ ਹਨ?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"ਛੱਡੋ"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"ਸੋਧ ਕਰਦੇ ਰਹੋ"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"ਰੱਦ ਕਰੋ"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"ਸੰਪਰਕ ਖੋਜੋ"</string>
<string name="title_edit_group" msgid="8602752287270586734">"ਸੰਪਰਕ ਹਟਾਓ"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"ਇਸਦੇ ਬਾਰੇ"</string>
<string name="send_message" msgid="8938418965550543196">"ਸੁਨੇਹਾ ਭੇਜੋ"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"ਇੱਕ ਨਿੱਜੀ ਕਾਪੀ ਬਣਾ ਰਿਹਾ ਹੈ..."</string>
- <string name="yesterday" msgid="6840858548955018569">"ਕੱਲ੍ਹ"</string>
<string name="tomorrow" msgid="6241969467795308581">"ਕੱਲ੍ਹ ਨੂੰ"</string>
<string name="today" msgid="8041090779381781781">"ਅੱਜ"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"ਅੱਜ <xliff:g id="TIME_INTERVAL">%s</xliff:g> ਵਜੇ"</string>
@@ -342,4 +341,506 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"ਸੁਨੇਹੇ"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"ਆਪਣੀ ਸੂਚੀ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"ਲੇਬਲ ਅਨੁਸਾਰ ਡੁਪਲੀਕੇਟ ਅਤੇ ਸਮੂਹ ਸੰਪਰਕ ਸਾਫ਼ ਕਰੋ"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"ਟੈਕਸਟ ਕਾਪੀ ਕੀਤਾ"</string>
+ <string name="copy_text" msgid="3257145021583508761">"ਕਲਿਪਬੋਰਡ ਤੇ ਕਾਪੀ ਕਰੋ"</string>
+ <!-- no translation found for call_custom (7756571794763171802) -->
+ <skip />
+ <!-- no translation found for call_home (1990519474420545392) -->
+ <skip />
+ <!-- no translation found for call_mobile (7502236805487609178) -->
+ <skip />
+ <!-- no translation found for call_work (5328785911463744028) -->
+ <skip />
+ <!-- no translation found for call_fax_work (7467763592359059243) -->
+ <skip />
+ <!-- no translation found for call_fax_home (8342175628887571876) -->
+ <skip />
+ <!-- no translation found for call_pager (9003902812293983281) -->
+ <skip />
+ <!-- no translation found for call_other (8563753966926932052) -->
+ <skip />
+ <!-- no translation found for call_callback (1910165691349426858) -->
+ <skip />
+ <!-- no translation found for call_car (3280537320306436445) -->
+ <skip />
+ <!-- no translation found for call_company_main (6105120947138711257) -->
+ <skip />
+ <!-- no translation found for call_isdn (1541590690193403411) -->
+ <skip />
+ <!-- no translation found for call_main (6082900571803441339) -->
+ <skip />
+ <!-- no translation found for call_other_fax (5745314124619636674) -->
+ <skip />
+ <!-- no translation found for call_radio (8296755876398357063) -->
+ <skip />
+ <!-- no translation found for call_telex (2223170774548648114) -->
+ <skip />
+ <!-- no translation found for call_tty_tdd (8951266948204379604) -->
+ <skip />
+ <!-- no translation found for call_work_mobile (8707874281430105394) -->
+ <skip />
+ <!-- no translation found for call_work_pager (3419348514157949008) -->
+ <skip />
+ <!-- no translation found for call_assistant (2141641383068514308) -->
+ <skip />
+ <!-- no translation found for call_mms (6274041545876221437) -->
+ <skip />
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <!-- no translation found for sms_custom (5932736853732191825) -->
+ <skip />
+ <!-- no translation found for sms_home (7524332261493162995) -->
+ <skip />
+ <!-- no translation found for sms_mobile (5200107250451030769) -->
+ <skip />
+ <!-- no translation found for sms_work (2269624156655267740) -->
+ <skip />
+ <!-- no translation found for sms_fax_work (8028189067816907075) -->
+ <skip />
+ <!-- no translation found for sms_fax_home (9204042076306809634) -->
+ <skip />
+ <!-- no translation found for sms_pager (7730404569637015192) -->
+ <skip />
+ <!-- no translation found for sms_other (806127844607642331) -->
+ <skip />
+ <!-- no translation found for sms_callback (5004824430094288752) -->
+ <skip />
+ <!-- no translation found for sms_car (7444227058437359641) -->
+ <skip />
+ <!-- no translation found for sms_company_main (118970873419678087) -->
+ <skip />
+ <!-- no translation found for sms_isdn (8153785037515047845) -->
+ <skip />
+ <!-- no translation found for sms_main (8621625784504541679) -->
+ <skip />
+ <!-- no translation found for sms_other_fax (3888842199855843152) -->
+ <skip />
+ <!-- no translation found for sms_radio (3329166673433967820) -->
+ <skip />
+ <!-- no translation found for sms_telex (9034802430065267848) -->
+ <skip />
+ <!-- no translation found for sms_tty_tdd (6782284969132531532) -->
+ <skip />
+ <!-- no translation found for sms_work_mobile (2459939960512702560) -->
+ <skip />
+ <!-- no translation found for sms_work_pager (5566924423316960597) -->
+ <skip />
+ <!-- no translation found for sms_assistant (2773424339923116234) -->
+ <skip />
+ <!-- no translation found for sms_mms (4069352461380762677) -->
+ <skip />
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation_title (766292372438450432) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <!-- no translation found for clearFrequentsProgress_title (5157001637482794212) -->
+ <skip />
+ <!-- no translation found for status_available (5586870015822828392) -->
+ <skip />
+ <!-- no translation found for status_away (1838861100379804730) -->
+ <skip />
+ <!-- no translation found for status_busy (9147992455450257136) -->
+ <skip />
+ <string name="contactsList" msgid="8661624236494819731">"ਸੰਪਰਕ"</string>
+ <!-- no translation found for local_invisible_directory (6046691709127661065) -->
+ <skip />
+ <!-- no translation found for directory_search_label (1887759056597975053) -->
+ <skip />
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <!-- no translation found for local_search_label (2551177578246113614) -->
+ <skip />
+ <string name="search_results_searching" msgid="3984833028938569930">"ਖੋਜ ਰਿਹਾ ਹੈ..."</string>
+ <!-- no translation found for foundTooManyContacts (5163335650920020220) -->
+ <skip />
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"ਕੋਈ ਸੰਪਰਕ ਨਹੀਂ"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ਮਿਲਿਆ</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ਮਿਲਿਆ</item>
+ </plurals>
+ <!-- no translation found for description_quick_contact_for (6737516415168327789) -->
+ <skip />
+ <!-- no translation found for missing_name (8745511583852904385) -->
+ <skip />
+ <!-- no translation found for favoritesFrequentContacted (6184232487472425690) -->
+ <skip />
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"ਸੰਪਰਕ ਦੇਖੋ"</string>
+ <!-- no translation found for list_filter_phones (735313795643493365) -->
+ <skip />
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <!-- no translation found for view_updates_from_group (1782685984905600034) -->
+ <skip />
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <!-- no translation found for nameLabelsGroup (2034640839640477827) -->
+ <skip />
+ <!-- no translation found for nicknameLabelsGroup (2891682101053358010) -->
+ <skip />
+ <!-- no translation found for full_name (6602579550613988977) -->
+ <skip />
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <!-- no translation found for name_prefix (59756378548779822) -->
+ <skip />
+ <!-- no translation found for name_middle (8467433655992690326) -->
+ <skip />
+ <!-- no translation found for name_suffix (3855278445375651441) -->
+ <skip />
+ <!-- no translation found for name_phonetic (4259595234312430484) -->
+ <skip />
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <!-- no translation found for name_phonetic_middle (8643721493320405200) -->
+ <skip />
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <!-- no translation found for phoneLabelsGroup (6468091477851199285) -->
+ <skip />
+ <!-- no translation found for emailLabelsGroup (8389931313045344406) -->
+ <skip />
+ <!-- no translation found for postalLabelsGroup (3487738141112589324) -->
+ <skip />
+ <!-- no translation found for imLabelsGroup (3898238486262614027) -->
+ <skip />
+ <!-- no translation found for organizationLabelsGroup (2478611760751832035) -->
+ <skip />
+ <!-- no translation found for relationLabelsGroup (1854373894284572781) -->
+ <skip />
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <!-- no translation found for sms (1756857139634224222) -->
+ <skip />
+ <!-- no translation found for postal_address (8765560217149624536) -->
+ <skip />
+ <!-- no translation found for ghostData_company (5414421120553765775) -->
+ <skip />
+ <!-- no translation found for ghostData_title (7496735200318496110) -->
+ <skip />
+ <!-- no translation found for label_notes (8337354953278341042) -->
+ <skip />
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <!-- no translation found for websiteLabelsGroup (4202998982804009261) -->
+ <skip />
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <!-- no translation found for email_home (8573740658148184279) -->
+ <skip />
+ <!-- no translation found for email_mobile (2042889209787989814) -->
+ <skip />
+ <!-- no translation found for email_work (2807430017302722689) -->
+ <skip />
+ <!-- no translation found for email_other (3454004077967657109) -->
+ <skip />
+ <!-- no translation found for email_custom (7548003991586214105) -->
+ <skip />
+ <!-- no translation found for email (5668400997660065897) -->
+ <skip />
+ <!-- no translation found for postal_street (8133143961580058972) -->
+ <skip />
+ <!-- no translation found for postal_pobox (4431938829180269821) -->
+ <skip />
+ <!-- no translation found for postal_neighborhood (1450783874558956739) -->
+ <skip />
+ <!-- no translation found for postal_city (6597491300084895548) -->
+ <skip />
+ <!-- no translation found for postal_region (6045263193478437672) -->
+ <skip />
+ <!-- no translation found for postal_postcode (572136414136673751) -->
+ <skip />
+ <!-- no translation found for postal_country (7638264508416368690) -->
+ <skip />
+ <!-- no translation found for map_home (1243547733423343982) -->
+ <skip />
+ <!-- no translation found for map_work (1360474076921878088) -->
+ <skip />
+ <!-- no translation found for map_other (3817820803587012641) -->
+ <skip />
+ <!-- no translation found for map_custom (6184363799976265281) -->
+ <skip />
+ <!-- no translation found for chat_aim (2588492205291249142) -->
+ <skip />
+ <!-- no translation found for chat_msn (8041633440091073484) -->
+ <skip />
+ <!-- no translation found for chat_yahoo (6629211142719943666) -->
+ <skip />
+ <!-- no translation found for chat_skype (1210045020427480566) -->
+ <skip />
+ <!-- no translation found for chat_qq (4294637812847719693) -->
+ <skip />
+ <!-- no translation found for chat_gtalk (981575737258117697) -->
+ <skip />
+ <!-- no translation found for chat_icq (8438405386153745775) -->
+ <skip />
+ <!-- no translation found for chat_jabber (7561444230307829609) -->
+ <skip />
+ <!-- no translation found for chat (9025361898797412245) -->
+ <skip />
+ <!-- no translation found for description_minus_button (6908099247930477551) -->
+ <skip />
+ <!-- no translation found for expand_collapse_name_fields_description (8682630859539604311) -->
+ <skip />
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <!-- no translation found for list_filter_all_accounts (8908683398914322369) -->
+ <skip />
+ <!-- no translation found for list_filter_all_starred (5031734941601931356) -->
+ <skip />
+ <!-- no translation found for list_filter_customize (4789963356004169321) -->
+ <skip />
+ <!-- no translation found for list_filter_single (5871400283515893087) -->
+ <skip />
+ <!-- no translation found for display_ungrouped (6885954210243119591) -->
+ <skip />
+ <!-- no translation found for display_all_contacts (2031647544742889505) -->
+ <skip />
+ <!-- no translation found for menu_sync_remove (3266725887008450161) -->
+ <skip />
+ <!-- no translation found for dialog_sync_add (8267045393119375803) -->
+ <skip />
+ <!-- no translation found for display_more_groups (2682547080423434170) -->
+ <skip />
+ <!-- no translation found for display_warn_remove_ungrouped (8872290721676651414) -->
+ <skip />
+ <!-- no translation found for savingDisplayGroups (2133152192716475939) -->
+ <skip />
+ <!-- no translation found for menu_done (796017761764190697) -->
+ <skip />
+ <!-- no translation found for menu_doNotSave (58593876893538465) -->
+ <skip />
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <!-- no translation found for import_from_sim (3859272228033941659) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <!-- no translation found for cancel_import_confirmation_message (3929951040347726757) -->
+ <skip />
+ <!-- no translation found for cancel_export_confirmation_message (1995462401949262638) -->
+ <skip />
+ <!-- no translation found for cancel_vcard_import_or_export_failed (6139900383366166706) -->
+ <skip />
+ <!-- no translation found for fail_reason_unknown (1714092345030570863) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_open_file (2067725459821997463) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_initialize_exporter (707260459259688510) -->
+ <skip />
+ <!-- no translation found for fail_reason_no_exportable_contact (8728506011371262065) -->
+ <skip />
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <!-- no translation found for fail_reason_error_occurred_during_export (3018855323913649063) -->
+ <skip />
+ <!-- no translation found for fail_reason_too_long_filename (3393764245254738333) -->
+ <skip />
+ <!-- no translation found for fail_reason_io_error (6748358842976073255) -->
+ <skip />
+ <!-- no translation found for fail_reason_low_memory_during_import (875222757734882898) -->
+ <skip />
+ <!-- no translation found for fail_reason_vcard_parse_error (888263542360355784) -->
+ <skip />
+ <!-- no translation found for fail_reason_not_supported (8219562769267148825) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_collect_vcard_meta_info (6427931733267328564) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title (4767045779458185251) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_canceled_title (2652222370493306887) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <!-- no translation found for composer_failed_to_get_database_infomation (1765944280846236723) -->
+ <skip />
+ <!-- no translation found for composer_has_no_exportable_contact (3296493229040294335) -->
+ <skip />
+ <!-- no translation found for composer_not_initialized (2321648986367005254) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_title (4892358112409576342) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_message (4938527850142003141) -->
+ <skip />
+ <!-- no translation found for importing_vcard_description (4245275224298571351) -->
+ <skip />
+ <!-- no translation found for reading_vcard_failed_title (4251647443358422855) -->
+ <skip />
+ <!-- no translation found for reading_vcard_canceled_title (1925216585981542019) -->
+ <skip />
+ <!-- no translation found for importing_vcard_finished_title (3341541727268747967) -->
+ <skip />
+ <!-- no translation found for importing_vcard_canceled_title (2147475978165599336) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message (2804911199145873396) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message_with_default_name (1022969530654129470) -->
+ <skip />
+ <!-- no translation found for vcard_import_request_rejected_message (2890471184508516011) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message (2210241345252081463) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <!-- no translation found for vcard_export_request_rejected_message (2844874826431327531) -->
+ <skip />
+ <!-- no translation found for vcard_unknown_filename (7171709890959915954) -->
+ <skip />
+ <!-- no translation found for caching_vcard_message (4926308675041506756) -->
+ <skip />
+ <!-- no translation found for vcard_import_failed (5223531255894842406) -->
+ <skip />
+ <!-- no translation found for nfc_vcard_file_name (2823095213265993609) -->
+ <skip />
+ <!-- no translation found for confirm_export_title (6834385377255286349) -->
+ <skip />
+ <!-- no translation found for caching_vcard_title (1226272312940516605) -->
+ <skip />
+ <!-- no translation found for progress_notifier_message (2311011466908220528) -->
+ <skip />
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"ਸੈਟਿੰਗਾਂ"</string>
+ <!-- no translation found for share_visible_contacts (890150378880783797) -->
+ <skip />
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <!-- no translation found for dialog_import_export (4360648034889921624) -->
+ <skip />
+ <!-- no translation found for dialog_import (2431698729761448759) -->
+ <skip />
+ <!-- no translation found for share_error (948429331673358107) -->
+ <skip />
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <!-- no translation found for menu_search (9147752853603483719) -->
+ <skip />
+ <!-- no translation found for menu_contacts_filter (2165153460860262501) -->
+ <skip />
+ <!-- no translation found for activity_title_contacts_filter (8275542497615516969) -->
+ <skip />
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <!-- no translation found for contactsFavoritesLabel (8417039765586853670) -->
+ <skip />
+ <!-- no translation found for listTotalAllContactsZero (5513001821794568211) -->
+ <skip />
+ <!-- no translation found for menu_clear_frequents (7688250191932838833) -->
+ <skip />
+ <!-- no translation found for menu_select_sim (3603578201960504010) -->
+ <skip />
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <!-- no translation found for menu_import_export (26217871113229507) -->
+ <skip />
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"ਬਲੌਕ ਕੀਤੇ ਨੰਬਰ"</string>
+ <!-- no translation found for contact_status_update_attribution (752179367353018597) -->
+ <skip />
+ <!-- no translation found for contact_status_update_attribution_with_date (7358045508107825068) -->
+ <skip />
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"ਖੋਜ ਹਟਾਓ"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index e652f6e..ad13c2f 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -246,9 +246,9 @@
<string name="set_default" msgid="4417505153468300351">"Ustaw jako wartość domyślną"</string>
<string name="clear_default" msgid="7193185801596678067">"Wyczyść wartość domyślną"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Tekst skopiowany"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Odrzucić zmiany i zakończyć edycję?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Odrzucić zmiany?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Odrzuć"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Edytuj dalej"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Anuluj"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Szukaj kontaktów"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Usuń kontakty"</string>
@@ -273,7 +273,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Informacje"</string>
<string name="send_message" msgid="8938418965550543196">"Wyślij wiadomość"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Tworzenie kopii osobistej…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Wczoraj"</string>
<string name="tomorrow" msgid="6241969467795308581">"Jutro"</string>
<string name="today" msgid="8041090779381781781">"Dzisiaj"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Dzisiaj: <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -364,4 +363,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Wiadomości"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Porządkuj listę kontaktów"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Usuwaj duplikaty i grupuj kontakty według etykiet"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Tekst skopiowany"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopiuj do schowka"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Połącz – <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Połącz – domowy"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Połącz – komórka"</string>
+ <string name="call_work" msgid="5328785911463744028">"Połącz – służbowy"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Połącz – faks służbowy"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Połącz – faks domowy"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Połącz – pager"</string>
+ <string name="call_other" msgid="8563753966926932052">"Zadzwoń"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Zadzwoń – połączenie zwrotne"</string>
+ <string name="call_car" msgid="3280537320306436445">"Połącz – samochód"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Połącz – 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="5745314124619636674">"Zadzwoń – faks"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Połącz – 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">"Połącz – służbowa komórka"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Połącz – 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">"Połącz – MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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">"SMS – komórka"</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="806127844607642331">"SMS"</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="3888842199855843152">"SMS – 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żbowa komórka"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Wyczyścić częste kontakty?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Czyszczę częste kontakty…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Dostępny"</string>
+ <string name="status_away" msgid="1838861100379804730">"Nieobecny"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Zajęty"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontakty"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Inne"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Katalog"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Wszystkie kontakty"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Wyszukiwanie…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Znaleziono więcej niż <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Brak kontaktów"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> znalezione</item>
+ <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> znalezionych</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> znalezionego</item>
+ <item quantity="one">1 znaleziony</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Szybki kontakt: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Bez nazwy)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Częste kontakty"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Wyświetl kontakt"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Wszystkie kontakty z numerami telefonów"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Pokaż aktualizacje"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nazwa"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Pseudonim"</string>
+ <string name="full_name" msgid="6602579550613988977">"Imię i nazwisko"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Nazwisko (fonetycznie)"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Drugie imię (fonetycznie)"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mail"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adres"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Komunikatory"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizacja"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relacja"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"SMS"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adres"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Firma"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Stanowisko"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notatki"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Adres witryny"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"E-mail – domowy"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"E-mail – komórka"</string>
+ <string name="email_work" msgid="2807430017302722689">"E-mail – służbowy"</string>
+ <string name="email_other" msgid="3454004077967657109">"E-mail"</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="postal_street" msgid="8133143961580058972">"Ulica"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Skrytka pocztowa"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Dzielnica"</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="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="3817820803587012641">"Wyświetl 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="description_minus_button" msgid="6908099247930477551">"usuń"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Rozwiń lub zwiń pola imion i nazwisk"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Wszystkie kontakty"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Oznaczone gwiazdką"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Dostosuj"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontakt"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Wszystkie inne kontakty"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Wszystkie kontakty"</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_warn_remove_ungrouped" msgid="8872290721676651414">"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="savingDisplayGroups" msgid="2133152192716475939">"Trwa zapisywanie opcji wyświetlania..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Gotowe"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Anuluj"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importuj z karty SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Anulować import: <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Anulować eksport: <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Nie można anulować importu/eksportu vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Nieznany błąd."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Nie można otworzyć pliku „<xliff:g id="FILE_NAME">%s</xliff:g>”: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Nie można uruchomić programu eksportującego: „<xliff:g id="EXACT_REASON">%s</xliff:g>”."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Brak kontaktów, które można wyeksportować."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Wystąpił błąd podczas eksportowania: „<xliff:g id="EXACT_REASON">%s</xliff:g>”."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Wymagana nazwa pliku jest zbyt długa („<xliff:g id="FILENAME">%s</xliff:g>”)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Błąd wejścia/wyjścia"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Za mało pamięci. Plik może być zbyt duży."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Nie można przeanalizować pliku vCard z nieoczekiwanego powodu."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Format nie jest obsługiwany."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Nie można zebrać metainformacji z podanych plików vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Nie można zaimportować co najmniej jednego pliku (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Zakończono eksportowanie pliku <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Anulowano eksportowanie pliku <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Eksportowanie danych kontaktowych"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Nie można pobrać informacji z bazy danych."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Brak kontaktów do eksportu. Jeśli masz w telefonie kontakty, być może dostawcy danych nie zezwalają na ich eksport z telefonu."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Obiekt tworzenia danych vCard nie został uruchomiony poprawnie."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Eksport nieudany"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Dane kontaktów nie zostały wyeksportowane.\nPrzyczyna: „<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importowanie <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Nie można odczytać danych vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Anulowano odczyt danych kart vCard"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Zakończono importowanie pliku vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Anulowano importowanie pliku <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Plik <xliff:g id="FILENAME">%s</xliff:g> zostanie za chwilę zaimportowany."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Plik zostanie za chwilę zaimportowany."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Żądanie importu danych vCard zostało odrzucone. Spróbuj ponownie później."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Plik <xliff:g id="FILENAME">%s</xliff:g> zostanie za chwilę wyeksportowany."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Żądanie eksportu danych vCard zostało odrzucone. Spróbuj ponownie później."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontakt"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Trwa buforowanie plików vCard w lokalnym obszarze tymczasowym. Właściwy import rozpocznie się za chwilę."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Nie można zaimportować pliku vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Odebrane przez NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Eksport kontaktów?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Buforowanie"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importowanie <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Ustawienia"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Udostępnij widoczne kontakty"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importuj/eksportuj kontakty"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importuj kontakty"</string>
+ <string name="share_error" msgid="948429331673358107">"Tego kontaktu nie można udostępniać."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Szukaj"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kontakty do wyświetlenia"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kontakty do wyświetlenia"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Ulubione"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Brak kontaktów"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Wyczyść częste kontakty"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Wybierz kartę SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importuj/eksportuj"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Zablokowane numery"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"przez: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g>, przez: <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Wyczyść wyszukiwanie"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml
index c57de4c..6b354de 100644
--- a/res/values-pt-rBR/strings.xml
+++ b/res/values-pt-rBR/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Definir padrão"</string>
<string name="clear_default" msgid="7193185801596678067">"Limpar padrão"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Descartar as alterações e sair da edição?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Descartar alterações?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Descartar"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Continuar edição"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Cancelar"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Pesquisar contatos"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Remover contatos"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Sobre"</string>
<string name="send_message" msgid="8938418965550543196">"Enviar mensagem"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Criando uma cópia pessoal..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Ontem"</string>
<string name="tomorrow" msgid="6241969467795308581">"Amanhã"</string>
<string name="today" msgid="8041090779381781781">"Hoje"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Hoje, às <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mensagens"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organizar sua lista"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Limpe as cópias e agrupe os contatos por marcador"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copiar para área de transferência"</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="8563753966926932052">"Chamar"</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="5745314124619636674">"Chamar 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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Enviar SMS para <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Enviar SMS para resid."</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Enviar SMS para celular"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Enviar SMS para tel. comercial"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Enviar SMS para fax com."</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Enviar SMS para fax resid."</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Enviar SMS para o pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"Enviar SMS"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Enviar SMS para retorno de chamada"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Enviar SMS para o carro"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Enviar SMS para empresa (principal)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Mandar mensagem de texto para ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Enviar SMS para núm. principal"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Enviar SMS para fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Enviar SMS para o rádio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Enviar SMS para telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Enviar SMS para TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Enviar SMS para cel. comercial"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Enviar SMS para pager com."</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 texto MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Apagar contatos frequentes?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Apagando contatos frequentes…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Disponível"</string>
+ <string name="status_away" msgid="1838861100379804730">"Ausente"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Ocupado"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contatos"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Outros"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Diretório"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Todos os contatos"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Pesquisando..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Mais de <xliff:g id="COUNT">%d</xliff:g> encontrados."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Nenhum contato"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> encontrados</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> encontrados</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Contato rápido de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"Sem nome"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Chamados frequentemente"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Visualizar contato"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Todos os contatos com números de telefone"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Ver atualizações"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nome"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Apelido"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nome"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Nome fonético"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Nome do meio fonético"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefone"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mail"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Endereço"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Mensagem instantânea"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organização"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relacionamento"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Mensagem de texto"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Endereço"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Título"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Observações"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Site"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"E-mail"</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="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="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="3817820803587012641">"Visualizar 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="description_minus_button" msgid="6908099247930477551">"excluir"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Expandir ou recolher campos de nome"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Todos os contatos"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Com estrela"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personalizar"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contato"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Todos os outros contatos"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Todos os contatos"</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_warn_remove_ungrouped" msgid="8872290721676651414">"A remoção de \"<xliff:g id="GROUP">%s</xliff:g>\" da sincronização também removerá os contatos não agrupados da sincronização."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Salvando opções de exibição…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Concluído"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Cancelar"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importar do cartão SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Cancelar importação de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Cancelar exportação de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Não foi poss. canc. imp./export. vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Erro desconhecido."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"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="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Não foi possível iniciar o exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Não há contato exportáveis."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Ocorreu um erro durante a exportação: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"O nome de arquivo exigido é muito longo (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Erro E/S"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Não há memória suficiente. O arquivo pode ser muito grande."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Não foi possível analisar o vCard por um motivo inesperado."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"O formato não é suportado."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Não foi possível coletar informações meta de determinados arquivos vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Um ou mais arquivos não puderam ser importados (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Exportação concluída de <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exportação de <xliff:g id="FILENAME">%s</xliff:g> cancelada."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportando dados do contato"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Não foi possível obter as informações do banco de dados."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Não há contatos exportáveis. Se você tiver contatos em seu telefone, alguns provedores de dados podem não permitir que os contatos sejam exportados a partir do telefone."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"O criador do vCard não iniciou corretamente."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Não foi possível exportar"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Os dados de contato não foram exportados.\nMotivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importando <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Não foi possível ler os dados do vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Leitura de dados vCard cancelada"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Importação de vCard concluída <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importação de <xliff:g id="FILENAME">%s</xliff:g> cancelada"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> será importado em breve."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"O arquivo será importado em breve."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"O pedido de importação vCard foi rejeitado. Tente novamente mais tarde."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> será exportado em breve."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Pedido de exportação vCard foi rejeitado. Tente novamente mais tarde."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contato"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Armazenando VCard(s) em cache no armazenamento temporário local. A importação real começará em breve."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Não foi possível importar o vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contato via NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exportar contatos?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Armazenando em cache"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importando <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Configurações"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Compartilhar contatos visíveis"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importar/Exportar contatos"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importar contatos"</string>
+ <string name="share_error" msgid="948429331673358107">"Este contato não pode ser compartilhado."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Pesquisa"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contatos para exibição"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contatos a exibir"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Nenhum contato."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Apagar frequentes"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Selecionar cartão SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importar/Exportar"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Números bloqueados"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"por meio de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Limpar pesquisa"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 4219e08..b3f268a 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Definir a predefinição"</string>
<string name="clear_default" msgid="7193185801596678067">"Limpar predefinição"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Pretende rejeitar as alterações e sair do editor?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Rejeitar alterações?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Rejeitar"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Continuar a editar"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Cancelar"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Pesquisar contactos"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Remover contactos"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Acerca de"</string>
<string name="send_message" msgid="8938418965550543196">"Enviar mensagem"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"A criar uma cópia pessoal"</string>
- <string name="yesterday" msgid="6840858548955018569">"Ontem"</string>
<string name="tomorrow" msgid="6241969467795308581">"Amanhã"</string>
<string name="today" msgid="8041090779381781781">"Hoje"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Hoje, às <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mensagens"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organizar a sua lista"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Limpar duplicados e agrupar contactos por etiqueta"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copiar para área de transf."</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="8563753966926932052">"Ligar"</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="5745314124619636674">"Ligar para número de 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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Enviar SMS para"</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="3888842199855843152">"Enviar SMS para número de 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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Limpar contactos frequentes?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"A limpar contactos frequentes..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Available"</string>
+ <string name="status_away" msgid="1838861100379804730">"Ausente"</string>
+ <string name="status_busy" msgid="9147992455450257136">"ocupado"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contactos"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Outro"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Directório"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Todos os contactos"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"A pesquisar..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Foram encontrados mais de <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Sem contactos"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> encontrados</item>
+ <item quantity="one">1 encontrado</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Contacto rápido de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Sem nome)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Contactos frequentes"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Ver contacto"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Todos os contactos com números de telefone"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Ver atualizações"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nome"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Pseudónimo"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nome"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Nome fonético"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonética do primeiro apelido"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefone"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Email"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Endereço"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"MI"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organização"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relacionamento"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Mensagem de texto"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Endereço"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Título"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notas"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Web site"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"Email"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Enviar e-mail a <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Email"</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="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="3817820803587012641">"Ver endereço"</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="description_minus_button" msgid="6908099247930477551">"eliminar"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Expandir ou reduzir campos de nomes"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Todos os contactos"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Marcado com estrela"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personalizar"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contacto"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Todos os outros contactos"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Todos os contactos"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Ao remover \"<xliff:g id="GROUP">%s</xliff:g>\" da sincronização, removerá também quaisquer contactos não agrupados."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"A guardar opções de visualização..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Concluído"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Cancelar"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importar do cartão SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Cancelar a importação de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Cancelar a exportação de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Imposs. cancel. import./export. do vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Erro desconhecido."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"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="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Não foi possível iniciar o exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Não existe um contacto exportável."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Ocorreu um erro durante a exportação: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Nome de ficheiro demasiado longo (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Erro de E/S"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Memória insuficiente. O ficheiro pode ser demasiado grande."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Não foi possível analisar o vCard por um motivo inesperado."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"O formato não é suportado."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Não foi possível recolher meta informações de determinado(s) ficheiro(s) vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Não foi possível importar um ou mais ficheiros (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"A exportação de <xliff:g id="FILENAME">%s</xliff:g> terminou."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"A exportação de <xliff:g id="FILENAME">%s</xliff:g> foi cancelada."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportar dados do contacto"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Não foi possível obter informações da base de dados"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Não existem contactos exportáveis. Se tiver contactos no seu telemóvel, alguns fornecedores de dados podem não permitir a exportação dos contactos a partir do telemóvel."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"O compositor vCard não iniciou corretamente."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Impossível exportar"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Os dados do contacto não foram exportados.\nMotivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"A importar <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Não foi possível ler dados do vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"A leitura de dados vCard foi cancelada"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"A importação do vCard terminou <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"A importação de <xliff:g id="FILENAME">%s</xliff:g> foi cancelada"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> será importado em breve."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"O ficheiro será importado em breve."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"O pedido de importação do vCard foi rejeitado. Tente novamente mais tarde."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> será exportado em breve."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"O pedido de exportação do vCard foi rejeitado. Tente novamente mais tarde."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contacto"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"A colocar vCard(s) em cache no armazenamento temporário local. A importação efetiva começará brevemente."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Não foi possível importar o vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contacto recebido através de NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exportar contactos?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"A colocar em cache"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"A importar <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Definições"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Partilhar contactos visíveis"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importar/export. contactos"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importar contactos"</string>
+ <string name="share_error" msgid="948429331673358107">"Não é possível partilhar este contacto."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Pesquisar"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contactos a apresentar"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contactos a apresentar"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Sem contactos."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Limpar frequentes"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Selecionar cartão SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importar/exportar"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Números bloqueados"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"através do <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> através do <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Limpar pesquisa"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index c57de4c..6b354de 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Definir padrão"</string>
<string name="clear_default" msgid="7193185801596678067">"Limpar padrão"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Descartar as alterações e sair da edição?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Descartar alterações?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Descartar"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Continuar edição"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Cancelar"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Pesquisar contatos"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Remover contatos"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Sobre"</string>
<string name="send_message" msgid="8938418965550543196">"Enviar mensagem"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Criando uma cópia pessoal..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Ontem"</string>
<string name="tomorrow" msgid="6241969467795308581">"Amanhã"</string>
<string name="today" msgid="8041090779381781781">"Hoje"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Hoje, às <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mensagens"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organizar sua lista"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Limpe as cópias e agrupe os contatos por marcador"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Texto copiado"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copiar para área de transferência"</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="8563753966926932052">"Chamar"</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="5745314124619636674">"Chamar 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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Enviar SMS para <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Enviar SMS para resid."</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Enviar SMS para celular"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Enviar SMS para tel. comercial"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Enviar SMS para fax com."</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Enviar SMS para fax resid."</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Enviar SMS para o pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"Enviar SMS"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Enviar SMS para retorno de chamada"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Enviar SMS para o carro"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Enviar SMS para empresa (principal)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Mandar mensagem de texto para ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Enviar SMS para núm. principal"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Enviar SMS para fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Enviar SMS para o rádio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Enviar SMS para telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Enviar SMS para TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Enviar SMS para cel. comercial"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Enviar SMS para pager com."</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 texto MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Apagar contatos frequentes?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Apagando contatos frequentes…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Disponível"</string>
+ <string name="status_away" msgid="1838861100379804730">"Ausente"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Ocupado"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Contatos"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Outros"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Diretório"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Todos os contatos"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Pesquisando..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Mais de <xliff:g id="COUNT">%d</xliff:g> encontrados."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Nenhum contato"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> encontrados</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> encontrados</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Contato rápido de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"Sem nome"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Chamados frequentemente"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Visualizar contato"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Todos os contatos com números de telefone"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Ver atualizações"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nome"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Apelido"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nome"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Nome fonético"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Nome do meio fonético"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefone"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mail"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Endereço"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Mensagem instantânea"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organização"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relacionamento"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Mensagem de texto"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Endereço"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Empresa"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Título"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Observações"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Site"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"E-mail"</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="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="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="3817820803587012641">"Visualizar 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="description_minus_button" msgid="6908099247930477551">"excluir"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Expandir ou recolher campos de nome"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Todos os contatos"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Com estrela"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personalizar"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contato"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Todos os outros contatos"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Todos os contatos"</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_warn_remove_ungrouped" msgid="8872290721676651414">"A remoção de \"<xliff:g id="GROUP">%s</xliff:g>\" da sincronização também removerá os contatos não agrupados da sincronização."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Salvando opções de exibição…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Concluído"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Cancelar"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importar do cartão SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Cancelar importação de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Cancelar exportação de <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Não foi poss. canc. imp./export. vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Erro desconhecido."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"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="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Não foi possível iniciar o exportador: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Não há contato exportáveis."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Ocorreu um erro durante a exportação: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"O nome de arquivo exigido é muito longo (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Erro E/S"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Não há memória suficiente. O arquivo pode ser muito grande."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Não foi possível analisar o vCard por um motivo inesperado."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"O formato não é suportado."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Não foi possível coletar informações meta de determinados arquivos vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Um ou mais arquivos não puderam ser importados (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Exportação concluída de <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exportação de <xliff:g id="FILENAME">%s</xliff:g> cancelada."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exportando dados do contato"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Não foi possível obter as informações do banco de dados."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Não há contatos exportáveis. Se você tiver contatos em seu telefone, alguns provedores de dados podem não permitir que os contatos sejam exportados a partir do telefone."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"O criador do vCard não iniciou corretamente."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Não foi possível exportar"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Os dados de contato não foram exportados.\nMotivo: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importando <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Não foi possível ler os dados do vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Leitura de dados vCard cancelada"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Importação de vCard concluída <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importação de <xliff:g id="FILENAME">%s</xliff:g> cancelada"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> será importado em breve."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"O arquivo será importado em breve."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"O pedido de importação vCard foi rejeitado. Tente novamente mais tarde."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> será exportado em breve."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Pedido de exportação vCard foi rejeitado. Tente novamente mais tarde."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contato"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Armazenando VCard(s) em cache no armazenamento temporário local. A importação real começará em breve."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Não foi possível importar o vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Contato via NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exportar contatos?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Armazenando em cache"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importando <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Configurações"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Compartilhar contatos visíveis"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importar/Exportar contatos"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importar contatos"</string>
+ <string name="share_error" msgid="948429331673358107">"Este contato não pode ser compartilhado."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Pesquisa"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Contatos para exibição"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Contatos a exibir"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoritos"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Nenhum contato."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Apagar frequentes"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Selecionar cartão SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importar/Exportar"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Números bloqueados"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"por meio de <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Limpar pesquisa"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 0ed0842..e689032 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -239,9 +239,9 @@
<string name="set_default" msgid="4417505153468300351">"Setați ca prestabilit"</string>
<string name="clear_default" msgid="7193185801596678067">"Ștergeți datele prestabilite"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Text copiat"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Renunțați la modificări și părăsiți editarea?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Renunțați la modificări?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Renunțați"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Editați în continuare"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Anulați"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Căutați în Agendă"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Eliminați intrările din Agendă"</string>
@@ -266,7 +266,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Despre"</string>
<string name="send_message" msgid="8938418965550543196">"Trimiteți mesajul"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Se creează o copie personală..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Ieri"</string>
<string name="tomorrow" msgid="6241969467795308581">"Mâine"</string>
<string name="today" msgid="8041090779381781781">"Astăzi"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Astăzi, la <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -353,4 +352,335 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mesaje"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organizați-vă lista"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Eliminați dublurile și grupați persoanele de contact după etichetă"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Text copiat"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Copiați în clipboard"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Apelați <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Apelați numărul de domiciliu"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Apelați numărul de mobil"</string>
+ <string name="call_work" msgid="5328785911463744028">"Apelați numărul de serviciu"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Apelați un număr de fax de serviciu"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Apelați un număr de fax de la domiciliu"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Apelați un număr de pager"</string>
+ <string name="call_other" msgid="8563753966926932052">"Apelați"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Apelați un număr cu apelare inversă"</string>
+ <string name="call_car" msgid="3280537320306436445">"Apelați numărul de mașină"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Apelați numărul principal al companiei"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Apelați ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Apelați numărul principal"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Apelați numărul de fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Apelați un număr radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Apelați un număr de telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Apelați TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Apelați numărul de mobil de la serviciu"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Apelați pagerul de serviciu"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Apelați <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Apelați MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Trimiteți mesaj text către <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Trimiteți mesaj text către telefonul de domiciliu"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Trimiteți mesaj text către telefonul mobil"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Trimiteți mesaj text către numărul de serviciu"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Trimiteți mesaj text către un fax de serviciu"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Trimiteți mesaj text către un număr de fax de domiciliu"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Trimiteți mesaj text către un număr de pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"Mesaj"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Trimiteți un mesaj text către un număr cu apelare inversă"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Trimiteți mesaj text către un număr de telefon de mașină"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Trimiteți mesaj text către numărul principal al companiei"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Mesaj text către un număr ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Trimiteți mesaj text către numărul principal"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Trimiteți mesaj text către un număr de fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Trimiteți mesaj text către un număr radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Trimiteți mesaj text către un număr de telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Trimiteți mesaj text către TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Trimiteți mesaj text către numărul de mobil de serviciu"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Trimiteți mesaj text către un număr de pager de la serviciu"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Trimiteți mesaj text către <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Trimiteți mesaj text către un număr MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Ștergeți persoane frecvent contactate?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Ștergeți persoane frecv. contactate…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Disponibil(ă)"</string>
+ <string name="status_away" msgid="1838861100379804730">"Plecat(ă)"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Ocupat(ă)"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Agendă"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Altul"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Director"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Toată Agenda"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Se caută..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"S-au găsit peste <xliff:g id="COUNT">%d</xliff:g> (de) persoane din agendă."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Nu există persoane în agendă"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> persoane de contact găsite</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> de persoane de contact găsite</item>
+ <item quantity="one">O persoană de contact găsită</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Contact rapid pentru <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Fără nume)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Frecvent contactate"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Afișați persoana din agendă"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Toate persoanele din agendă cu numere de telefon"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Afișați actualizări"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Nume"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Pseudonim"</string>
+ <string name="full_name" msgid="6602579550613988977">"Nume"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Prefixul numelui"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Al doilea prenume"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Sufixul numelui"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Nume fonetic"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Numele mijlociu fonetic"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-mail"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adresă"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizație"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relație"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Mesaj text"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adresă"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Companie"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titlu"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Note"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Site web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Trimiteți un e-mai la o adresă de e-mail de domiciliu"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Trimiteți un e-mail către un telefon mobil"</string>
+ <string name="email_work" msgid="2807430017302722689">"Trimiteți e-mail către adresa de serviciu"</string>
+ <string name="email_other" msgid="3454004077967657109">"Trimiteți un e-mail"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Trimiteți e-mail către <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Trimiteți un e-mail"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Stradă"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Căsuța poștală"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Vecinătate"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Oraș"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Stat"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Codul ZIP"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Țara"</string>
+ <string name="map_home" msgid="1243547733423343982">"Vizualizați adresa de domiciliu"</string>
+ <string name="map_work" msgid="1360474076921878088">"Vizualizați adresa de serviciu"</string>
+ <string name="map_other" msgid="3817820803587012641">"Vizualizați adresa poștală"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Vizualizați adresa <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Conversați prin AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Conversați prin Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Conversați prin Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Conversați prin Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Conversați prin QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Conversați prin Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Conversați prin ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Conversați prin Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Conversați prin chat"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"ștergeți"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Extindeți sau restrângeți câmpurile pentru nume"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Toată agenda"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Cu stea"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Personalizați"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Persoană din agendă"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Toate celelalte contacte"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Toată Agenda"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Eliminați grup de sincronizare"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Adăugați grup de sincronizare"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Mai multe grupuri..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Eliminarea grupului „<xliff:g id="GROUP">%s</xliff:g>” din sincronizare va elimina, de asemenea, orice persoană din agendă care nu face parte dintr-un grup."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Se salvează opțiunile de afișare..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Terminat"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Anulați"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importați de pe cardul SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Anulați importul fișierului <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Anulați exportul fișierului <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Anulare import/export vCard nereușită"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Eroare necunoscută."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Nu s-a putut deschide fișierul „<xliff:g id="FILE_NAME">%s</xliff:g>”: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Nu s-a putut iniţializa instrumentul de export: „<xliff:g id="EXACT_REASON">%s</xliff:g>”"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Nicio persoană de contact exportabilă."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"A apărut o eroare în timpul exportului: „<xliff:g id="EXACT_REASON">%s</xliff:g>”."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Numele de fișier solicitat este prea lung („<xliff:g id="FILENAME">%s</xliff:g>”)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Eroare I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Memoria este insuficientă (probabil fișierul este prea mare)."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Nu s-au putut analiza datele de pe vCard dintr-un motiv neașteptat."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Formatul nu este acceptat."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Nu s-au putut colecta metainformaţiile pentru fișierele vCard indicate."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Unul sau mai multe fișiere nu s-au putut importa (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"S-a finalizat exportul fișierului <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exportul fișierului <xliff:g id="FILENAME">%s</xliff:g> a fost anulat."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Se exportă datele persoanelor din agendă"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Nu s-au putut obține informații din baza de date."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Nu există persoane din agendă care să poată fi exportate. Dacă aveți persoane în agenda telefonului, este posibil ca exportul acestora de pe telefon să fie interzis de unii furnizori de date."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Compozitorul vCard nu a pornit în mod corespunzător."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Nu s-a putut exporta"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Datele de contact nu au fost exportate.\nMotivul: „<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Se importă <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Nu s-au putut citi datele de pe vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Citirea datelor vCard a fost anulată"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"S-a finalizat importul vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importul fișierului <xliff:g id="FILENAME">%s</xliff:g> a fost anulat"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> va fi importat în curând."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Fișierul va fi importat în scurt timp."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Solicitarea de importare a fișierului vCard a fost respinsă. Încercați din nou mai târziu."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> va fi exportat în curând."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Solicitarea de exportare a fișierului vCard a fost respinsă. Încercați din nou mai târziu."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contact"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Fișierele vCard se stochează în memoria cache într-un spațiu de stocare local temporar. Importul propriu-zis va începe în curând."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Nu s-a putut importa fișierul vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Cont.prim.pr.NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exportați Agenda?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Se stochează în cache"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Se importă <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Setări"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Distribuiți persoanele vizibile din agendă"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Import/export contacte"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importați Agenda"</string>
+ <string name="share_error" msgid="948429331673358107">"Această persoană de contact nu poate fi distribuită."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Căutați"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Persoane de contact de afişat"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Pers. din agendă de afiş."</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favorite"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Nicio persoană din agendă."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Șterg. pers. frecv. contact."</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Selectați cardul SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importați/exportați"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Numere blocate"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"de pe <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"La ora <xliff:g id="DATE">%1$s</xliff:g> de pe <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Ștergeți căutarea"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index e348274..2a89bb5 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -246,9 +246,9 @@
<string name="set_default" msgid="4417505153468300351">"Установить по умолчанию"</string>
<string name="clear_default" msgid="7193185801596678067">"Удалить настройки по умолчанию"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Текст скопирован"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Отменить изменения и завершить редактирование?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Отменить изменения?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Отменить"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Продолжить редактирование"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Отмена"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> (<xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>)"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Поиск контактов"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Удалить контакты"</string>
@@ -273,7 +273,6 @@
<string name="about_card_title" msgid="2920942314212825637">"О контакте"</string>
<string name="send_message" msgid="8938418965550543196">"Отправить сообщение"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Копирование..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Вчера"</string>
<string name="tomorrow" msgid="6241969467795308581">"Завтра"</string>
<string name="today" msgid="8041090779381781781">"Сегодня"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Сегодня, <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -364,4 +363,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Сообщения"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Наведите порядок в контактах"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Объедините контакты в группы и удалите повторения"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Текст скопирован"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Копировать в буфер обмена"</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="8563753966926932052">"Позвонить"</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="5745314124619636674">"Позвонить на номер факса"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Отправить 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="3888842199855843152">"Отправить 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">"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>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Очистить список популярных контактов?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Подождите…"</string>
+ <string name="status_available" msgid="5586870015822828392">"На месте"</string>
+ <string name="status_away" msgid="1838861100379804730">"Отсутствует"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Не беспокоить"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Контакты"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Другое"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Каталог"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Все контакты"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Поиск…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Найдено более <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Нет контактов"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one">Найден <xliff:g id="COUNT">%d</xliff:g> контакт</item>
+ <item quantity="few">Найдено <xliff:g id="COUNT">%d</xliff:g> контакта</item>
+ <item quantity="many">Найдено <xliff:g id="COUNT">%d</xliff:g> контактов</item>
+ <item quantity="other">Найдено <xliff:g id="COUNT">%d</xliff:g> контактов</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Быстрый вызов, контакт: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"Имя не указано"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Часто набираемые"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Данные контакта"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Все контакты с номерами телефонов"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Обновления"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Имя"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Псевдоним"</string>
+ <string name="full_name" msgid="6602579550613988977">"Имя"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Транскрипция имени"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Отчество (транскрипция)"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Телефон"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Адрес электронной почты"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Адрес"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Чат"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Организация"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Отношения"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Текстовое сообщение"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Адрес"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Название"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Должность"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Примечания"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Веб-сайт"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"Написать письмо"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Эл. почта (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="email" msgid="5668400997660065897">"Эл. почта"</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="map_home" msgid="1243547733423343982">"Просмотреть домашний адрес"</string>
+ <string name="map_work" msgid="1360474076921878088">"Просмотреть рабочий адрес"</string>
+ <string name="map_other" msgid="3817820803587012641">"Просмотр адреса"</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="description_minus_button" msgid="6908099247930477551">"удалить"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Показать/скрыть дополнительные поля"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Все контакты"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Помеченные"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Настроить"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Контакт"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Все контакты"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Все контакты"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Вместе с группой \"<xliff:g id="GROUP">%s</xliff:g>\" перестанут синхронизироваться контакты, не добавленные в группы."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Сохранение настроек..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Готово"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Отмена"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Импортировать с SIM-карты"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Отменить импорт файла \"<xliff:g id="FILENAME">%s</xliff:g>\"?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Отменить экспорт файла \"<xliff:g id="FILENAME">%s</xliff:g>\"?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Не удалось отменить импорт/экспорт vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Неизвестная ошибка"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Не удалось открыть файл \"<xliff:g id="FILE_NAME">%s</xliff:g>\". Причина: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Не удалось запустить функцию экспорта. Причина: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Нет контактов для экспорта."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Ошибка при экспорте. Причина: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Слишком длинное название: <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Ошибка ввода-вывода"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Недостаточно памяти. Возможно, файл слишком большой."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Не удалось проанализировать файл vCard."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Формат не поддерживается."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Не удалось собрать метаданные файлов VCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Не удалось импортировать один или несколько файлов (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Экспорт файла \"<xliff:g id="FILENAME">%s</xliff:g>\" завершен."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Экспорт файла \"<xliff:g id="FILENAME">%s</xliff:g>\" отменен."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Экспорт данных контакта"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"База данных недоступна."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Не найдены контакты для экспорта. Возможно, экспорт контактов с телефона не поддерживается поставщиком услуг передачи данных."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Сбой при запуске редактора vCard."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Сбой экспорта"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Не удалось экспортировать данные.\nПричина: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Импорт: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Ошибка чтения vCard-файла"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Чтение данных vCard отменено"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Импорт файла vCard <xliff:g id="FILENAME">%s</xliff:g> завершен"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Импорт файла \"<xliff:g id="FILENAME">%s</xliff:g>\" отменен"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Импорт <xliff:g id="FILENAME">%s</xliff:g> начнется в ближайшее время."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Файл будет импортирован в ближайшее время."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Запрос на импорт данных vCard отклонен. Повторите попытку позже."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Экспорт <xliff:g id="FILENAME">%s</xliff:g> начнется в ближайшее время."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Запрос на экспорт данных vCard отклонен. Повторите попытку позже."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"контакт"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Выполняется кеширование файлов vCard в локальное временное хранилище. Импорт скоро начнется."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Не удалось импортировать данные vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Получено по NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Экспорт контактов"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Кеширование"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Импорт <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Настройки"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Передать видимые контакты"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Импорт/экспорт контактов"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Импорт контактов"</string>
+ <string name="share_error" msgid="948429331673358107">"Не удалось передать данные."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Поиск"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Фильтр контактов"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Фильтр контактов"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Избранное"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Нет контактов"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Очистить популярные контакты"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Выбрать SIM-карту"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Импорт/экспорт"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Заблокированные номера"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"с помощью <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> с помощью <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Очистить условия поиска"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index 153d970..2ae29d2 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"සුපුරුදු ලෙස සකසන්න"</string>
<string name="clear_default" msgid="7193185801596678067">"සුපුරුදු හිස් කරන්න"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"පෙළ පිටපත් කරන ලදී"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"ඔබේ වෙනස් කිරීම් ඉවත දමා සංස්කරණය කිරීමෙන් ඉවත් වන්නද?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"වෙනස්කම් ඉවතලන්න ද?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"ඉවතලන්න"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"සංස්කරණය කරගෙන යන්න"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"අවලංගු කරන්න"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"සම්බන්ධතා සොයන්න"</string>
<string name="title_edit_group" msgid="8602752287270586734">"සම්බන්ධතා ඉවත් කරන්න"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"පිළිබඳ"</string>
<string name="send_message" msgid="8938418965550543196">"පණිවිඩය යවන්න"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"පුද්ගලික පිටපතක් නිර්මාණය කරමින්…"</string>
- <string name="yesterday" msgid="6840858548955018569">"ඊයේ"</string>
<string name="tomorrow" msgid="6241969467795308581">"හෙට"</string>
<string name="today" msgid="8041090779381781781">"අද"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"අද <xliff:g id="TIME_INTERVAL">%s</xliff:g> ට"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"පණිවිඩ"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"ඔබගේ ලැයිස්තුව සංවිධානය කරන්න"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"අනුපිටපත් පිරිසිදු කර, සම්බන්ධතා ලේබල අනුව සමූහ කරන්න"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"පෙළ පිටපත් කරන ලදී"</string>
+ <string name="copy_text" msgid="3257145021583508761">"පසුරු පුවරුවට පිටපත් කරන්න"</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="8563753966926932052">"ඇමතුම"</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="5745314124619636674">"ෆැක්ස් අමතන්න"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"පෙළ"</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="3888842199855843152">"ෆැක්ස් වෙත කෙටි පණිවිඩයක් යවන්න"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"නිතරම සම්බන්ධ වන අය හිස් කරන්නද?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"නිතරම සම්බන්ධ වන අය හිස් කරමින්…"</string>
+ <string name="status_available" msgid="5586870015822828392">"සිටියි"</string>
+ <string name="status_away" msgid="1838861100379804730">"ළඟ නැත"</string>
+ <string name="status_busy" msgid="9147992455450257136">"කාර්යබහුල"</string>
+ <string name="contactsList" msgid="8661624236494819731">"සම්බන්ධතා"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"වෙනත්"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"නාමාවලිය"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"සියලුම සම්බන්ධතා"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"සොයමින්..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g> ට වඩා සොයාගන්නා ලදී."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"සම්බන්ධතා නැත"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one">සොයා ගැනීම් <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="other">සොයා ගැනීම් <xliff:g id="COUNT">%d</xliff:g></item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> සඳහා ඉක්මන් සම්බන්ධතා"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(නමක් නොමැත)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"නිතරම සම්බන්ධ වන"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"සම්බන්ධතාව පෙන්වන්න"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"දුරකථන අංක සහිත සියලු සම්බන්ධතා"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"යාවත්කාලීන වීම් පෙන්වන්න"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"නම"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"අපනාමය"</string>
+ <string name="full_name" msgid="6602579550613988977">"නම"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"ස්වර නම"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"ස්වර මැද නම"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"දුරකථනය"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"ඊ-තැපෑල"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"ලිපිනය"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"සංවිධානය"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"ඥාතිත්වය"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"කෙටි පණිවුඩ"</string>
+ <string name="postal_address" msgid="8765560217149624536">"ලිපිනය"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"සමාගම"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"මාතෘකාව"</string>
+ <string name="label_notes" msgid="8337354953278341042">"සටහන්"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"වෙබ් අඩවිය"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"ඊ-තැපෑල"</string>
+ <string name="email_custom" msgid="7548003991586214105">"<xliff:g id="CUSTOM">%s</xliff:g> ඊ-තැපැල් කරන්න"</string>
+ <string name="email" msgid="5668400997660065897">"ඊ-තැපෑල"</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">"ZIP කේතය"</string>
+ <string name="postal_country" msgid="7638264508416368690">"රට"</string>
+ <string name="map_home" msgid="1243547733423343982">"නිවෙස් ලිපිනය පෙන්වන්න"</string>
+ <string name="map_work" msgid="1360474076921878088">"කාර්යාල ලිපිනය පෙන්වන්න"</string>
+ <string name="map_other" msgid="3817820803587012641">"ලිපිනය පෙන්වන්න"</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="description_minus_button" msgid="6908099247930477551">"මකන්න"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"නම් ක්ෂේත්ර විහිදන්න හෝ හකුළන්න"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"සියලුම සම්බන්ධතා"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"තරුව සලකුණු කළ"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"අභිරුචිකරණය"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"සම්බන්ධතාවය"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"සියලු වෙනත් සම්බන්ධතා"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"සියලුම සම්බන්ධතා"</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_warn_remove_ungrouped" msgid="8872290721676651414">"\"<xliff:g id="GROUP">%s</xliff:g>\" සමමුහුර්ත කිරීමෙන් ඉවත් කිරීමෙන් ඕනෑම කණ්ඩායම් නොකළ සම්බන්ධතා සමමුහුර්තයෙන් ඉවත් කරනු ඇත."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"පෙන්වීම් විකල්ප සුරකමින්…"</string>
+ <string name="menu_done" msgid="796017761764190697">"හරි"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"අවලංගු කරන්න"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM පතෙන් ආයාත කරන්න"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> ආයාත කිරීම අවලංගු කරන්නද?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> නිර්යාත කිරීම අවලංගු කරන්නද?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard ආයාත/නිර්යාත කිරීම අවලංගු කළ නොහැක"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"නොදන්නා දෝෂය."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" විවෘත කිරීමට නොහැක: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"නිර්යාතකරු පටන් ගැනීමට නොහැක: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"නිර්යාත කළ හැකි සම්බන්ධතාවයක් නොමැත."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"නිර්යාතය අතරතුර දෝෂයක් සිදු විය: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"අවශ්ය කරන ගොනු නම දිග වැඩිය (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O දෝෂය"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"මතකය මදිය. ගොනුව විශාල වැඩි විය හැක."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"බලාපොරොත්තු නොවූ හේතුවක් නිසා vCard ය විග්රහ කළ නොහැක."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"මෙම ආකෘතිය වෙත සහාය නොදක්වයි."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"ලබාදුන් vCard ගොනු(ව) වල පාර දත්ත එකතු කළ නොහැකි විය."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"ගොනු එකක් හෝ කිහිපයක් ආයාත කිරීමට නොහැකි විය (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> නිර්යාත කිරීම සම්පූර්ණ කෙරුණි."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> නිර්යාත කිරීම අවලංගු කෙරුණි."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"සම්බන්ධතා දත්ත නිර්යාත කිරීම"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"දත්ත සමුදායේ තොරතුරු ලබාගත නොහැක."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"නිර්යාත කළ හැකි සම්බන්ධතා නැත. ඔබගේ දුරකථනයේ සම්බන්ධතා තිබේ නම්, සමහර දත්ත සපයන්නන් දුරකථනයෙන් සම්බන්ධතා නිර්යාත කිරීමට අවසර ලබා නොදිය හැක."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard සකසනය නිවැරදිව පටන් ගත්තේ නැත."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"නිර්යාත කළ නොහැකිය"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"සම්බන්ධතා දත්ත නිර්යාත නොකරන ලදි.\nහේතුව: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> ආයාත කරමින්"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard දත්ත කියවිය නොහැක"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard දත්ත කියවීම අවලංගු කෙරුණි"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g> ආයාත කිරීම සම්පූර්ණ විය"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> ආයාත කිරීම අවලංගු කෙරුණි"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> කෙටි වේලාවකින් ආයාත වනු ඇත."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"ගොනුව කෙටි වේලාවකින් ආයාත කරනු ඇත."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard ආයාත අයැදුම ප්රතික්ෂේප කරන ලදි. පසුව නැවත උත්සාහ කරන්න."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> කෙටි වේලාවකින් නිර්යාත කරනු ඇත."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard නිර්යාත ඉල්ලීම ප්රතික්ෂේප කරන ලදි. පසුව නැවත උත්සාහ කරන්න."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"සම්බන්ධතාවය"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"පෙදෙසි තාවකාලික ආචයනයට vCard(s) හැඹිලිගත කරමින් පවතී. සැබෑ ආයාත කිරීම ඉක්මනින් පටන් ගනු ඇත."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard ආයාත කිරීමට නොහැක."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC හරහා සම්බන්ධතාව ලැබුණි"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"සම්බන්ධතා නිර්යාත කරන්නද?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"හැඹිලි ගත කරමින්"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g> ආයාත කරමින්"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"සැකසීම්"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"දෘශ්ය සම්බන්ධතා බෙදාගන්න"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"සම්බන්ධතා ආයාත/නිර්යාත කිරීම"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"සම්බන්ධතා ආයාත කරන්න"</string>
+ <string name="share_error" msgid="948429331673358107">"මෙම සම්බන්ධතාව බෙදා ගත නොහැක."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"සෙවීම"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"පෙන්වීමට සම්බන්ධතා"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"පෙන්වීමට සම්බන්ධතා"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"ප්රියතම"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"සම්බන්ධතා නැත."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"නිතරමයන් හිස් කරන්න"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM කාඩ්පත තෝරන්න"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"ආයාත/නිර්යාත"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"අවහිර කළ අංක"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g> හරහා"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="SOURCE">%2$s</xliff:g> ඔස්සේ <xliff:g id="DATE">%1$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"සෙවීම හිස් කරන්න"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index cfd7f9c..2710f97 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -246,9 +246,9 @@
<string name="set_default" msgid="4417505153468300351">"Nastaviť ako predvolené"</string>
<string name="clear_default" msgid="7193185801596678067">"Vymazať predvolené nastavenia"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Text bol skopírovaný"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Zahodiť zmeny a ukončiť upravovanie?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Zahodiť zmeny?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Zahodiť"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Pokračovať v úprave"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Zrušiť"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Hľadať v kontaktoch"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Odstránenie kontaktov"</string>
@@ -273,7 +273,6 @@
<string name="about_card_title" msgid="2920942314212825637">"O karte"</string>
<string name="send_message" msgid="8938418965550543196">"Odoslať správu"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Prebieha vytváranie osobnej kópie..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Včera"</string>
<string name="tomorrow" msgid="6241969467795308581">"Zajtra"</string>
<string name="today" msgid="8041090779381781781">"Dnes"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Dnes o <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -364,4 +363,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Správy"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Uporiadajte si zoznam"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Vymažte duplikáty a zoskupte kontakty podľa štítkov"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Text bol skopírovaný"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopírovať do schránky"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Zavolať kontakt <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Zavolať domov"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Zavolať na mobil"</string>
+ <string name="call_work" msgid="5328785911463744028">"Zavolať do práce"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Zavolať na pracovný fax"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Zavolať na domáci fax"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Zavolať na pager"</string>
+ <string name="call_other" msgid="8563753966926932052">"Zavolať"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Zavolať na číslo spätného volania"</string>
+ <string name="call_car" msgid="3280537320306436445">"Zavolať do auta"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Zavolať firme (hlavné číslo)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Zavolať na číslo ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Zavolať na hlavné číslo"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Zavolať na fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Zavolať rádiostanicu"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Zavolať na číslo Telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Zavolať na číslo TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Zavolať na pracovný mobil"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Zavolať na pracovný pager"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Zavolať kontaktu <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Zavolať na číslo MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Poslať správu kontaktu <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"SMS domov"</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áci fax"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"SMS na pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"Text"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Poslať správu na číslo spätného volania"</string>
+ <string name="sms_car" msgid="7444227058437359641">"SMS do auta"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Odoslať správu do firmy (hlavné)"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Poslať správu na číslo ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Odoslať správu na hlavné číslo"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"SMS na fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"SMS na rádiotelefón"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Poslať správu na číslo Telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Odoslať správu na číslo TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Odoslať správu na pracovný mobil"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Odoslať správu na pracovný pager"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Poslať správu kontaktu <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"SMS na číslo MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Vymazať často kontaktované osoby?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Mazanie často kontaktovaných osôb."</string>
+ <string name="status_available" msgid="5586870015822828392">"K dispozícii"</string>
+ <string name="status_away" msgid="1838861100379804730">"Preč"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Zaneprázdnený"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontakty"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Iné"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Adresár"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Všetky kontakty"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Hľadá sa…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Našlo sa viac ako <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Žiadne kontakty"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> nájdené položky</item>
+ <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> nájdenej položky</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> nájdených položiek</item>
+ <item quantity="one">1 nájdená položka</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Rýchly kontakt <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Bez mena)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Najčastejšie používané kontakty"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Zobraziť kontakt"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Všetky kontakty s telefónnymi číslami"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Zobraziť aktualizácie"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Meno"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Prezývka"</string>
+ <string name="full_name" msgid="6602579550613988977">"Meno"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Titul pred menom"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Druhé meno"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Titul za menom"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Meno (foneticky)"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Druhé meno (foneticky)"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefón"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Poslať e-mail"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adresa"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Okamžité správy"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizácia"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Vzťah"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Textová správa"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adresa"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Spoločnosť"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titul"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Poznámky"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Webové stránky"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"E-mail domov"</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="3454004077967657109">"Poslať e-mail"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Poslať e-mail osobe <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Poslať e-mail"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Ulica"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Číslo poštovej schránky"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Štvrť"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Mesto"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Štát"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"PSČ"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Krajina"</string>
+ <string name="map_home" msgid="1243547733423343982">"Zobraziť adresu domov"</string>
+ <string name="map_work" msgid="1360474076921878088">"Zobraziť pracovnú adresu"</string>
+ <string name="map_other" msgid="3817820803587012641">"Zobraziť adresu"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Zobraziť adresu <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Zhovárať sa pomocou služby AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Zhovárať sa pomocou služby Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Zhovárať sa pomocou služby Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Zhovárať sa pomocou služby Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Zhovárať sa pomocou služby QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Zhovárať sa pomocou aplikácie Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Zhovárať sa pomocou služby ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Zhovárať sa pomocou služby Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Rozhovor"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"odstrániť"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Rozbaliť alebo zbaliť polia mien"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Všetky kontakty"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Označené hviezdičkou"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Prispôsobiť"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontakt"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Všetky ostatné kontakty"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Všetky kontakty"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Odstrániť synchronizovanú skupinu"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Pridať synchronizovanú skupinu"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Ďalšie skupiny..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Ak zo synchronizácie odstránite skupinu „<xliff:g id="GROUP">%s</xliff:g>“, odstránite zo synchronizácie aj všetky kontakty, ktoré nie sú zaradené do žiadnej skupiny."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Prebieha ukladanie možností zobrazenia..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Hotovo"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Zrušiť"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importovať z SIM karty"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Zrušiť importovanie súboru <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Zrušiť exportovanie súboru <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Importovanie/exportovanie karty vizitky vCard zlyhalo"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Neznáma chyba."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Súbor „<xliff:g id="FILE_NAME">%s</xliff:g>“ sa nepodarilo otvoriť: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Nástroj na exportovanie sa nepodarilo spustiť: „<xliff:g id="EXACT_REASON">%s</xliff:g>“."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Nedá sa exportovať žiadny kontakt."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Počas exportovania sa vyskytla chyba: „<xliff:g id="EXACT_REASON">%s</xliff:g>“."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Požadovaný názov súboru (<xliff:g id="FILENAME">%s</xliff:g>) je príliš dlhý."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Chyba I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Nedostatok pamäte. Súbor je možno príliš veľký."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Analýza karty vCard zlyhala z neznámeho dôvodu."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Formát nie je podporovaný."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Metaúdaje daných súborov vizitiek vCard sa nepodarilo zhromaždiť."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Nepodaril sa import jedného alebo viacerých súborov (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Exportovanie súboru <xliff:g id="FILENAME">%s</xliff:g> bolo dokončené."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exportovanie súboru <xliff:g id="FILENAME">%s</xliff:g> bolo zrušené."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Export údajov kontaktov"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Nepodarilo sa získať informácie z databázy."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Nenašli sa žiadne kontakty, ktoré by bolo možné exportovať. Ak v telefóne skutočne máte kontakty, problém môže byť spôsobený tým, že niektorí poskytovatelia údajov nemusia umožňovať export kontaktov z telefónu."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Nástroj na tvorbu vizitiek vCard sa nespustil správne."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Export sa nepodaril"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Údaje o kontaktoch neboli exportované.\nDôvod: „<xliff:g id="FAIL_REASON">%s</xliff:g>“"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importuje sa <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Nepodarilo sa prečítať údaje vizitky vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Čítanie údajov vizitky vCard bolo zrušené"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Import vizitky vCard bol dokončený <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importovanie súboru <xliff:g id="FILENAME">%s</xliff:g> bolo zrušené"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Vizitka <xliff:g id="FILENAME">%s</xliff:g> bude čoskoro importovaná."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Súbor bude čoskoro importovaný."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Žiadosť o import vizitky vCard bola odmietnutá. Skúste to znova neskôr."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Vizitka <xliff:g id="FILENAME">%s</xliff:g> bude čoskoro exportovaná."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Žiadosť o exportovanie vizitky vCard bola odmietnutá. Skúste to znova neskôr."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontakt"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Prebieha načítavanie vizitiek vCard do vyrovnávacej pamäte miestneho dočasného úložiska. Samotné importovanie začne o chvíľu."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Vizitku vCard sa nepodarilo importovať."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kontakt cez NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exportovať kontakty?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Ukladanie do vyrovnávacej pamäte..."</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Import: <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Nastavenia"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Zdieľať viditeľné kontakty"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importovať alebo exportovať kontakty"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Import kontaktov"</string>
+ <string name="share_error" msgid="948429331673358107">"Tento kontakt nie je možné zdieľať."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Hľadať"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kontakty na zobrazenie"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kontakty na zobrazenie"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Obľúbené"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Žiadne kontakty."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Vymazať často kontakt. osoby"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Vybrať SIM kartu"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Import a export"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blokované čísla"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">", zdroj: <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g>, zdroj: <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Vymazať vyhľadávanie"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index fcaf9bf..01263d6 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -246,9 +246,9 @@
<string name="set_default" msgid="4417505153468300351">"Nastavi za privzeto"</string>
<string name="clear_default" msgid="7193185801596678067">"Počisti privzeto"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Besedilo kopirano"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Želite zavreči spremembe in prenehati urejati?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Želite zavreči spremembe?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Zavrzi"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Nadaljevanje urejanja"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Prekliči"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Iščite med stiki"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Odstranitev stikov"</string>
@@ -273,7 +273,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Vizitka"</string>
<string name="send_message" msgid="8938418965550543196">"Pošlji sporočilo"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Ustvarjanje osebne kopije ..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Včeraj"</string>
<string name="tomorrow" msgid="6241969467795308581">"Jutri"</string>
<string name="today" msgid="8041090779381781781">"Danes"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Danes ob <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -364,4 +363,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Sporočila"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organiziranje seznama"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Počistite dvojnike in povežite stike v skupine z oznakami"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Besedilo kopirano"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopiraj v odložišče"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Pokliči <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Pokliči domov"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Pokliči mobilni telefon"</string>
+ <string name="call_work" msgid="5328785911463744028">"Pokliči v službo"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Pokliči službeni faks"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Pokliči domači faks"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Pokliči pozivnik"</string>
+ <string name="call_other" msgid="8563753966926932052">"Pokliči"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Pokliči številko za povratni klic"</string>
+ <string name="call_car" msgid="3280537320306436445">"Pokliči telefon v avtu"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Pokliči glavno telefonsko številko podjetja"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Pokliči številko ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Pokliči glavno telefonsko številko"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Pokliči faks"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Pokliči radijski telefon"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Pokliči telefaks"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Pokliči številko TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Pokliči službeni mobilni telefon"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Pokliči službeni pozivnik"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Pokliči <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Pokliči telefon MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Pošlji SMS na številko <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Pošlji SMS domov"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Pošlji SMS na mobilni telefon"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Pošlji SMS na službeni telefon"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Pošlji SMS na službeni faks"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Pošlji SMS na domači faks"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Pošlji SMS na pozivnik"</string>
+ <string name="sms_other" msgid="806127844607642331">"Pošlji SMS"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Pošlji SMS na številko za povratni klic"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Pošlji SMS na telefon v avtu"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Pošlji SMS na glavno telefonsko številko podjetja"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Pošlji SMS na številko ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Pošlji SMS na glavno telefonsko številko"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Pošlji SMS na faks"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Pošlji SMS na radijski telefon"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Pošlji SMS na telefaks"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Pošlji SMS na telefonsko številko TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Pošlji SMS na službeni mobilni telefon"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Pošlji SMS na službeni pozivnik"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Pošlji SMS <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Pošlji SMS na telefon MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Želite izbrisati seznam pog. stikov?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Brisanje seznama pogostih stikov …"</string>
+ <string name="status_available" msgid="5586870015822828392">"Dosegljiv"</string>
+ <string name="status_away" msgid="1838861100379804730">"Odsoten"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Zaseden"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Stiki"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Drugo"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Imenik"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Vsi stiki"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Iskanje ..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Najdenih je bilo več kot <xliff:g id="COUNT">%d</xliff:g> stikov."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Ni stikov"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> najden</item>
+ <item quantity="two"><xliff:g id="COUNT">%d</xliff:g> najdena</item>
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> najdeni</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> najdenih</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Hitri stik za <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Ni imena)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Pogosti stiki"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Ogled stika"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Vsi stiki s telefonskimi številkami"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Prikaz posodobitev"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Ime"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Vzdevek"</string>
+ <string name="full_name" msgid="6602579550613988977">"Ime"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Naziv"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Drugo ime"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Naziv (za imenom)"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Ime – fonetično"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Drugo ime – fonetično"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-pošta"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Naslov"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Neposredno sporočanje"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organizacija"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Odnos"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"SMS"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Naslov"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Podjetje"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Naslov"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Opombe"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Spletno mesto"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Pošlji e-pošto domov"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Pošlji e-pošto na mobilni telefon"</string>
+ <string name="email_work" msgid="2807430017302722689">"Pošlji e-pošto na službeni naslov"</string>
+ <string name="email_other" msgid="3454004077967657109">"E-pošta"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Pošlji e-pošto na <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"E-pošta"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Ulica"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Poštni predal"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Naselje"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Mesto"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Država/regija"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Poštna številka"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Država"</string>
+ <string name="map_home" msgid="1243547733423343982">"Prikaži domači naslov"</string>
+ <string name="map_work" msgid="1360474076921878088">"Prikaži službeni naslov"</string>
+ <string name="map_other" msgid="3817820803587012641">"Prikaži naslov"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Prikaži naslov <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Klepet s storitvijo AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Klepet s storitvijo Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Klepet s storitvijo Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Klepet s storitvijo Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Klepet s storitvijo QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Klepet s storitvijo Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Klepet s storitvijo ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Klepet s storitvijo Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Klepet"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"brisanje"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Razširi ali strni imenska polja"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Vsi stiki"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Z zvezdico"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Prilagodi"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Stik"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Vsi drugi stiki"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Vsi stiki"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Odstrani skupino za sinhroniziranje"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Dodaj skupino za sinhroniziranje"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Več skupin ..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Če skupino »<xliff:g id="GROUP">%s</xliff:g>« odstranite iz sinhronizacije, boste iz sinhronizacije odstranili tudi vse nerazvrščene stike."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Shranjevanje možnosti prikaza..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Dokončano"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Prekliči"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Uvozi s kartice SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Želite preklicati izvoz datoteke <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Želite preklicati izvoz datoteke <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Uvoza/izvoza vCard ni mogoče preklicati"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Neznana napaka."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Datoteke »<xliff:g id="FILE_NAME">%s</xliff:g>« ni bilo mogoče odpreti: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Funkcije za izvoz ni bilo mogoče zagnati: »<xliff:g id="EXACT_REASON">%s</xliff:g>«"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Ni stikov za izvoz."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Pri izvozu je prišlo do napake: »<xliff:g id="EXACT_REASON">%s</xliff:g>«"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Zahtevano ime datoteke je predolgo (»<xliff:g id="FILENAME">%s</xliff:g>«)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Napaka I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Ni dovolj pomnilnika. Datoteka je morda prevelika."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Datoteke vCard iz neznanega razloga ni bilo mogoče razčleniti."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Ta oblika ni podprta."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Meta informacij za določene datoteke vCard ni bilo mogoče zbrati."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Ene ali več datotek ni bilo mogoče uvoziti (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Izvoz datoteke <xliff:g id="FILENAME">%s</xliff:g> je končan."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Izvoz datoteke <xliff:g id="FILENAME">%s</xliff:g> je preklican."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Izvažanje podatkov o stiku"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Informacij o zbirki podatkov ni bilo mogoče dobiti."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Ni na voljo stikov za izvoz. Če imate v telefonu stike, nekateri ponudniki podatkov morda ne omogočajo izvoza stikov iz telefona."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Urejevalnik za vCard se ni pravilno zagnal."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Izvoz ni mogoč"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Podatki stika niso bili izvoženi.\nRazlog: »<xliff:g id="FAIL_REASON">%s</xliff:g>«"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Uvažanje <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Podatkov vCard ni bilo mogoče prebrati"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Branje kartice vCard je preklicano"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Končan uvoz dat. vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Uvoz datoteke <xliff:g id="FILENAME">%s</xliff:g> je preklican"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Dat. <xliff:g id="FILENAME">%s</xliff:g> bo kmalu uvožena."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Datoteka bo kmalu uvožena."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Zahteva za uvoz datoteke vCard je bila zavrnjena. Poskusite znova pozneje."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Dat. <xliff:g id="FILENAME">%s</xliff:g> bo kmalu izvožena."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Zahteva za izvoz datoteke vCard je bila zavrnjena. Poskusite znova pozneje."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"stik"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Predpomnjenje datotek(e) vCARD v lokalno začasno shrambo. Dejanski uvoz se bo začel kmalu."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Datoteke vCard ni bilo mogoče uvoziti."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Stik prejet prek NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Želite izvoz. stike?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Predpomnjenje"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Uvažanje <xliff:g id="CURRENT_NUMBER">%s</xliff:g>(<xliff:g id="TOTAL_NUMBER">%s</xliff:g>:<xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Nastavitve"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Vidne stike deli z drugimi"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Uvoz/izvoz stikov"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Uvoz stikov"</string>
+ <string name="share_error" msgid="948429331673358107">"Tega stika ni mogoče dati v skupno rabo."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Iskanje"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Stiki, ki naj bodo prikazani"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Stiki za prikaz"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Priljubljeno"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Ni stikov."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Izbriši seznam pogostih stikov"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Izberite kartico SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Uvoz/izvoz"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blokirane številke"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"prek <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> prek <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Počisti iskalno polje"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
index 3095b66..f770adb 100644
--- a/res/values-sq-rAL/strings.xml
+++ b/res/values-sq-rAL/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Vendos të parazgjedhurën"</string>
<string name="clear_default" msgid="7193185801596678067">"Pastro të paracaktuarin"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Teksti u kopjua"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Hiqi ndryshimet dhe mbylle redaktimin?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Të injorohen ndryshimet?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Hiq"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Vazhdo redaktimin"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Anulo"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Kërko kontaktet"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Hiq kontaktet"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Informacion rreth"</string>
<string name="send_message" msgid="8938418965550543196">"Dërgo mesazh"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Po krijon një kopje personale..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Dje"</string>
<string name="tomorrow" msgid="6241969467795308581">"Nesër"</string>
<string name="today" msgid="8041090779381781781">"Sot"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Sot në <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,506 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mesazhet"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organizo listën tënde"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Pastro dublikatat dhe kontaktet e grupit sipas emërtimit"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Teksti u kopjua"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopjo në kujtesën e fragmenteve"</string>
+ <!-- no translation found for call_custom (7756571794763171802) -->
+ <skip />
+ <!-- no translation found for call_home (1990519474420545392) -->
+ <skip />
+ <!-- no translation found for call_mobile (7502236805487609178) -->
+ <skip />
+ <!-- no translation found for call_work (5328785911463744028) -->
+ <skip />
+ <!-- no translation found for call_fax_work (7467763592359059243) -->
+ <skip />
+ <!-- no translation found for call_fax_home (8342175628887571876) -->
+ <skip />
+ <!-- no translation found for call_pager (9003902812293983281) -->
+ <skip />
+ <!-- no translation found for call_other (8563753966926932052) -->
+ <skip />
+ <!-- no translation found for call_callback (1910165691349426858) -->
+ <skip />
+ <!-- no translation found for call_car (3280537320306436445) -->
+ <skip />
+ <!-- no translation found for call_company_main (6105120947138711257) -->
+ <skip />
+ <!-- no translation found for call_isdn (1541590690193403411) -->
+ <skip />
+ <!-- no translation found for call_main (6082900571803441339) -->
+ <skip />
+ <!-- no translation found for call_other_fax (5745314124619636674) -->
+ <skip />
+ <!-- no translation found for call_radio (8296755876398357063) -->
+ <skip />
+ <!-- no translation found for call_telex (2223170774548648114) -->
+ <skip />
+ <!-- no translation found for call_tty_tdd (8951266948204379604) -->
+ <skip />
+ <!-- no translation found for call_work_mobile (8707874281430105394) -->
+ <skip />
+ <!-- no translation found for call_work_pager (3419348514157949008) -->
+ <skip />
+ <!-- no translation found for call_assistant (2141641383068514308) -->
+ <skip />
+ <!-- no translation found for call_mms (6274041545876221437) -->
+ <skip />
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <!-- no translation found for sms_custom (5932736853732191825) -->
+ <skip />
+ <!-- no translation found for sms_home (7524332261493162995) -->
+ <skip />
+ <!-- no translation found for sms_mobile (5200107250451030769) -->
+ <skip />
+ <!-- no translation found for sms_work (2269624156655267740) -->
+ <skip />
+ <!-- no translation found for sms_fax_work (8028189067816907075) -->
+ <skip />
+ <!-- no translation found for sms_fax_home (9204042076306809634) -->
+ <skip />
+ <!-- no translation found for sms_pager (7730404569637015192) -->
+ <skip />
+ <!-- no translation found for sms_other (806127844607642331) -->
+ <skip />
+ <!-- no translation found for sms_callback (5004824430094288752) -->
+ <skip />
+ <!-- no translation found for sms_car (7444227058437359641) -->
+ <skip />
+ <!-- no translation found for sms_company_main (118970873419678087) -->
+ <skip />
+ <!-- no translation found for sms_isdn (8153785037515047845) -->
+ <skip />
+ <!-- no translation found for sms_main (8621625784504541679) -->
+ <skip />
+ <!-- no translation found for sms_other_fax (3888842199855843152) -->
+ <skip />
+ <!-- no translation found for sms_radio (3329166673433967820) -->
+ <skip />
+ <!-- no translation found for sms_telex (9034802430065267848) -->
+ <skip />
+ <!-- no translation found for sms_tty_tdd (6782284969132531532) -->
+ <skip />
+ <!-- no translation found for sms_work_mobile (2459939960512702560) -->
+ <skip />
+ <!-- no translation found for sms_work_pager (5566924423316960597) -->
+ <skip />
+ <!-- no translation found for sms_assistant (2773424339923116234) -->
+ <skip />
+ <!-- no translation found for sms_mms (4069352461380762677) -->
+ <skip />
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation_title (766292372438450432) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <!-- no translation found for clearFrequentsProgress_title (5157001637482794212) -->
+ <skip />
+ <!-- no translation found for status_available (5586870015822828392) -->
+ <skip />
+ <!-- no translation found for status_away (1838861100379804730) -->
+ <skip />
+ <!-- no translation found for status_busy (9147992455450257136) -->
+ <skip />
+ <string name="contactsList" msgid="8661624236494819731">"Kontaktet"</string>
+ <!-- no translation found for local_invisible_directory (6046691709127661065) -->
+ <skip />
+ <!-- no translation found for directory_search_label (1887759056597975053) -->
+ <skip />
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <!-- no translation found for local_search_label (2551177578246113614) -->
+ <skip />
+ <string name="search_results_searching" msgid="3984833028938569930">"Po kërkon..."</string>
+ <!-- no translation found for foundTooManyContacts (5163335650920020220) -->
+ <skip />
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Nuk ka asnjë kontakt"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">U gjetën <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="one">U gjet 1</item>
+ </plurals>
+ <!-- no translation found for description_quick_contact_for (6737516415168327789) -->
+ <skip />
+ <!-- no translation found for missing_name (8745511583852904385) -->
+ <skip />
+ <!-- no translation found for favoritesFrequentContacted (6184232487472425690) -->
+ <skip />
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Shiko kontaktin"</string>
+ <!-- no translation found for list_filter_phones (735313795643493365) -->
+ <skip />
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <!-- no translation found for view_updates_from_group (1782685984905600034) -->
+ <skip />
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <!-- no translation found for nameLabelsGroup (2034640839640477827) -->
+ <skip />
+ <!-- no translation found for nicknameLabelsGroup (2891682101053358010) -->
+ <skip />
+ <!-- no translation found for full_name (6602579550613988977) -->
+ <skip />
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <!-- no translation found for name_prefix (59756378548779822) -->
+ <skip />
+ <!-- no translation found for name_middle (8467433655992690326) -->
+ <skip />
+ <!-- no translation found for name_suffix (3855278445375651441) -->
+ <skip />
+ <!-- no translation found for name_phonetic (4259595234312430484) -->
+ <skip />
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <!-- no translation found for name_phonetic_middle (8643721493320405200) -->
+ <skip />
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <!-- no translation found for phoneLabelsGroup (6468091477851199285) -->
+ <skip />
+ <!-- no translation found for emailLabelsGroup (8389931313045344406) -->
+ <skip />
+ <!-- no translation found for postalLabelsGroup (3487738141112589324) -->
+ <skip />
+ <!-- no translation found for imLabelsGroup (3898238486262614027) -->
+ <skip />
+ <!-- no translation found for organizationLabelsGroup (2478611760751832035) -->
+ <skip />
+ <!-- no translation found for relationLabelsGroup (1854373894284572781) -->
+ <skip />
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <!-- no translation found for sms (1756857139634224222) -->
+ <skip />
+ <!-- no translation found for postal_address (8765560217149624536) -->
+ <skip />
+ <!-- no translation found for ghostData_company (5414421120553765775) -->
+ <skip />
+ <!-- no translation found for ghostData_title (7496735200318496110) -->
+ <skip />
+ <!-- no translation found for label_notes (8337354953278341042) -->
+ <skip />
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <!-- no translation found for websiteLabelsGroup (4202998982804009261) -->
+ <skip />
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <!-- no translation found for email_home (8573740658148184279) -->
+ <skip />
+ <!-- no translation found for email_mobile (2042889209787989814) -->
+ <skip />
+ <!-- no translation found for email_work (2807430017302722689) -->
+ <skip />
+ <!-- no translation found for email_other (3454004077967657109) -->
+ <skip />
+ <!-- no translation found for email_custom (7548003991586214105) -->
+ <skip />
+ <!-- no translation found for email (5668400997660065897) -->
+ <skip />
+ <!-- no translation found for postal_street (8133143961580058972) -->
+ <skip />
+ <!-- no translation found for postal_pobox (4431938829180269821) -->
+ <skip />
+ <!-- no translation found for postal_neighborhood (1450783874558956739) -->
+ <skip />
+ <!-- no translation found for postal_city (6597491300084895548) -->
+ <skip />
+ <!-- no translation found for postal_region (6045263193478437672) -->
+ <skip />
+ <!-- no translation found for postal_postcode (572136414136673751) -->
+ <skip />
+ <!-- no translation found for postal_country (7638264508416368690) -->
+ <skip />
+ <!-- no translation found for map_home (1243547733423343982) -->
+ <skip />
+ <!-- no translation found for map_work (1360474076921878088) -->
+ <skip />
+ <!-- no translation found for map_other (3817820803587012641) -->
+ <skip />
+ <!-- no translation found for map_custom (6184363799976265281) -->
+ <skip />
+ <!-- no translation found for chat_aim (2588492205291249142) -->
+ <skip />
+ <!-- no translation found for chat_msn (8041633440091073484) -->
+ <skip />
+ <!-- no translation found for chat_yahoo (6629211142719943666) -->
+ <skip />
+ <!-- no translation found for chat_skype (1210045020427480566) -->
+ <skip />
+ <!-- no translation found for chat_qq (4294637812847719693) -->
+ <skip />
+ <!-- no translation found for chat_gtalk (981575737258117697) -->
+ <skip />
+ <!-- no translation found for chat_icq (8438405386153745775) -->
+ <skip />
+ <!-- no translation found for chat_jabber (7561444230307829609) -->
+ <skip />
+ <!-- no translation found for chat (9025361898797412245) -->
+ <skip />
+ <!-- no translation found for description_minus_button (6908099247930477551) -->
+ <skip />
+ <!-- no translation found for expand_collapse_name_fields_description (8682630859539604311) -->
+ <skip />
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <!-- no translation found for list_filter_all_accounts (8908683398914322369) -->
+ <skip />
+ <!-- no translation found for list_filter_all_starred (5031734941601931356) -->
+ <skip />
+ <!-- no translation found for list_filter_customize (4789963356004169321) -->
+ <skip />
+ <!-- no translation found for list_filter_single (5871400283515893087) -->
+ <skip />
+ <!-- no translation found for display_ungrouped (6885954210243119591) -->
+ <skip />
+ <!-- no translation found for display_all_contacts (2031647544742889505) -->
+ <skip />
+ <!-- no translation found for menu_sync_remove (3266725887008450161) -->
+ <skip />
+ <!-- no translation found for dialog_sync_add (8267045393119375803) -->
+ <skip />
+ <!-- no translation found for display_more_groups (2682547080423434170) -->
+ <skip />
+ <!-- no translation found for display_warn_remove_ungrouped (8872290721676651414) -->
+ <skip />
+ <!-- no translation found for savingDisplayGroups (2133152192716475939) -->
+ <skip />
+ <!-- no translation found for menu_done (796017761764190697) -->
+ <skip />
+ <!-- no translation found for menu_doNotSave (58593876893538465) -->
+ <skip />
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <!-- no translation found for import_from_sim (3859272228033941659) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <!-- no translation found for cancel_import_confirmation_message (3929951040347726757) -->
+ <skip />
+ <!-- no translation found for cancel_export_confirmation_message (1995462401949262638) -->
+ <skip />
+ <!-- no translation found for cancel_vcard_import_or_export_failed (6139900383366166706) -->
+ <skip />
+ <!-- no translation found for fail_reason_unknown (1714092345030570863) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_open_file (2067725459821997463) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_initialize_exporter (707260459259688510) -->
+ <skip />
+ <!-- no translation found for fail_reason_no_exportable_contact (8728506011371262065) -->
+ <skip />
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <!-- no translation found for fail_reason_error_occurred_during_export (3018855323913649063) -->
+ <skip />
+ <!-- no translation found for fail_reason_too_long_filename (3393764245254738333) -->
+ <skip />
+ <!-- no translation found for fail_reason_io_error (6748358842976073255) -->
+ <skip />
+ <!-- no translation found for fail_reason_low_memory_during_import (875222757734882898) -->
+ <skip />
+ <!-- no translation found for fail_reason_vcard_parse_error (888263542360355784) -->
+ <skip />
+ <!-- no translation found for fail_reason_not_supported (8219562769267148825) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_collect_vcard_meta_info (6427931733267328564) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title (4767045779458185251) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_canceled_title (2652222370493306887) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <!-- no translation found for composer_failed_to_get_database_infomation (1765944280846236723) -->
+ <skip />
+ <!-- no translation found for composer_has_no_exportable_contact (3296493229040294335) -->
+ <skip />
+ <!-- no translation found for composer_not_initialized (2321648986367005254) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_title (4892358112409576342) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_message (4938527850142003141) -->
+ <skip />
+ <!-- no translation found for importing_vcard_description (4245275224298571351) -->
+ <skip />
+ <!-- no translation found for reading_vcard_failed_title (4251647443358422855) -->
+ <skip />
+ <!-- no translation found for reading_vcard_canceled_title (1925216585981542019) -->
+ <skip />
+ <!-- no translation found for importing_vcard_finished_title (3341541727268747967) -->
+ <skip />
+ <!-- no translation found for importing_vcard_canceled_title (2147475978165599336) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message (2804911199145873396) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message_with_default_name (1022969530654129470) -->
+ <skip />
+ <!-- no translation found for vcard_import_request_rejected_message (2890471184508516011) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message (2210241345252081463) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <!-- no translation found for vcard_export_request_rejected_message (2844874826431327531) -->
+ <skip />
+ <!-- no translation found for vcard_unknown_filename (7171709890959915954) -->
+ <skip />
+ <!-- no translation found for caching_vcard_message (4926308675041506756) -->
+ <skip />
+ <!-- no translation found for vcard_import_failed (5223531255894842406) -->
+ <skip />
+ <!-- no translation found for nfc_vcard_file_name (2823095213265993609) -->
+ <skip />
+ <!-- no translation found for confirm_export_title (6834385377255286349) -->
+ <skip />
+ <!-- no translation found for caching_vcard_title (1226272312940516605) -->
+ <skip />
+ <!-- no translation found for progress_notifier_message (2311011466908220528) -->
+ <skip />
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Cilësimet"</string>
+ <!-- no translation found for share_visible_contacts (890150378880783797) -->
+ <skip />
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <!-- no translation found for dialog_import_export (4360648034889921624) -->
+ <skip />
+ <!-- no translation found for dialog_import (2431698729761448759) -->
+ <skip />
+ <!-- no translation found for share_error (948429331673358107) -->
+ <skip />
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <!-- no translation found for menu_search (9147752853603483719) -->
+ <skip />
+ <!-- no translation found for menu_contacts_filter (2165153460860262501) -->
+ <skip />
+ <!-- no translation found for activity_title_contacts_filter (8275542497615516969) -->
+ <skip />
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <!-- no translation found for contactsFavoritesLabel (8417039765586853670) -->
+ <skip />
+ <!-- no translation found for listTotalAllContactsZero (5513001821794568211) -->
+ <skip />
+ <!-- no translation found for menu_clear_frequents (7688250191932838833) -->
+ <skip />
+ <!-- no translation found for menu_select_sim (3603578201960504010) -->
+ <skip />
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <!-- no translation found for menu_import_export (26217871113229507) -->
+ <skip />
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Numrat e bllokuar"</string>
+ <!-- no translation found for contact_status_update_attribution (752179367353018597) -->
+ <skip />
+ <!-- no translation found for contact_status_update_attribution_with_date (7358045508107825068) -->
+ <skip />
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Pastro kërkimin"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 49adda9..8e8db4a 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -115,7 +115,7 @@
<string name="attach_photo_dialog_title" msgid="5599827035558557169">"Слика контакта"</string>
<string name="customLabelPickerTitle" msgid="1081475101983255212">"Назив прилагођене ознаке"</string>
<string name="send_to_voicemail_checkbox" msgid="9001686764070676353">"Шаљи позиве директно у гласовну пошту"</string>
- <string name="removePhoto" msgid="4898105274130284565">"Уклони фотографију"</string>
+ <string name="removePhoto" msgid="4898105274130284565">"Уклони слику"</string>
<string name="noContacts" msgid="2228592924476426108">"Листа контаката је празна"</string>
<string name="noGroups" msgid="4607906327968232225">"Нема ознака."</string>
<string name="noAccounts" msgid="7768267764545265909">"Морате да имате налог да бисте могли да правите групе."</string>
@@ -160,7 +160,7 @@
<string name="callAgain" msgid="3197312117049874778">"Позови поново"</string>
<string name="returnCall" msgid="8171961914203617813">"Узврати позив"</string>
<string name="add_contact_dlg_message_fmt" msgid="7986472669444326576">"Желите ли да додате имејл адресу „<xliff:g id="EMAIL">%s</xliff:g>“ у контакте?"</string>
- <string name="description_contact_photo" msgid="3387458082667894062">"фотографија контакта"</string>
+ <string name="description_contact_photo" msgid="3387458082667894062">"слика контакта"</string>
<string name="description_plus_button" msgid="515164827856229880">"плус"</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>
@@ -191,8 +191,8 @@
<string name="google_account_type_format" msgid="5283997303922067997">"<xliff:g id="SOURCE">%1$s</xliff:g> налог"</string>
<!-- no translation found for from_account_format (4469138575127580203) -->
<skip />
- <string name="take_photo" msgid="7496128293167402354">"Сними фотографију"</string>
- <string name="take_new_photo" msgid="7341354729436576304">"Направи нову фотографију"</string>
+ <string name="take_photo" msgid="7496128293167402354">"Сликај"</string>
+ <string name="take_new_photo" msgid="7341354729436576304">"Сликај нову слику"</string>
<string name="pick_photo" msgid="2129509985223564942">"Изабери слику"</string>
<string name="pick_new_photo" msgid="9122450996263688237">"Изаберите нову слику"</string>
<string name="upgrade_in_progress" msgid="474511436863451061">"Контакт листа се ажурира."</string>
@@ -239,9 +239,9 @@
<string name="set_default" msgid="4417505153468300351">"Постави на подразумевано"</string>
<string name="clear_default" msgid="7193185801596678067">"Обриши подразумевану вредност"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Текст је копиран"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Желите ли да одбаците промене и прекинете са изменама?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Желите да одбаците промене?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Одбаци"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Настави изменe"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Откажи"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Претражите контакте"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Уклоните контакте"</string>
@@ -266,7 +266,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Основни подаци"</string>
<string name="send_message" msgid="8938418965550543196">"Пошаљи поруку"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Прављење личне копије..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Јуче"</string>
<string name="tomorrow" msgid="6241969467795308581">"Сутра"</string>
<string name="today" msgid="8041090779381781781">"Данас"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Данас у <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -353,4 +352,335 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Поруке"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Организујте листу"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Уклоните дупликате и групишите контакте према ознаци"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Текст је копиран"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Копирај у прив. меморију"</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="8563753966926932052">"Позови"</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="5745314124619636674">"Позови факс"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Teкст"</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="3888842199855843152">"Пошаљи 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">"Пошаљи SMS на TTY/TDD"</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">"Пошаљи SMS на <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Пошаљи SMS на MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Брисање често контактираних?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Брисање често контактираних..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Доступан/на"</string>
+ <string name="status_away" msgid="1838861100379804730">"Одсутан/на"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Заузет/а"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Контакти"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Други"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Каталог"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Сви контакти"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Претражује се..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Пронађено је више од <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Нема контаката"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one">пронађен је <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="few">пронађена су <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="other">пронађено је <xliff:g id="COUNT">%d</xliff:g></item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Брзи контакт за корисника <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Без имена)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Често контактирани"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Прикажи контакт"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Сви контакти са бројевима телефона"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Прикажи ажурирања"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Име"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Надимак"</string>
+ <string name="full_name" msgid="6602579550613988977">"Назив"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Име – фонетски"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Средње име – фонетски"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Телефон"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Пошаљи имејлом"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Адреса"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Размена тренутних порука"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Организација"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Однос"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Текстуална порука"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Адреса"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Предузеће"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Наслов"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Белешке"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Веб-сајт"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"Пошаљи имејлом"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Пошаљи имејл на адресу <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Пошаљи имејлом"</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="map_home" msgid="1243547733423343982">"Прикажи кућну адресу"</string>
+ <string name="map_work" msgid="1360474076921878088">"Прикажи пословну адресу"</string>
+ <string name="map_other" msgid="3817820803587012641">"Прикажи адресу"</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="description_minus_button" msgid="6908099247930477551">"избриши"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Проширивање или скупљање поља за име"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Сви контакти"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Са звездицом"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Прилагоди"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Контакт"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Сви други контакти"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Сви контакти"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Уклањањем групе „<xliff:g id="GROUP">%s</xliff:g>“ са листе за синхронизацију уклонићете и све негруписане контакте са те листе."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Чување опција приказа је у току..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Готово"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Откажи"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Увези са SIM картице"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Желите ли да откажете увоз датотеке <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Желите ли да откажете извоз датотеке <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Није могуће отказати vCard увоз/извоз"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Непозната грешка."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Није могуће отворити датотеку „<xliff:g id="FILE_NAME">%s</xliff:g>“: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Није могуће покренути програм за извоз: „<xliff:g id="EXACT_REASON">%s</xliff:g>“"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Нема контаката за извоз."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Дошло је до грешке при извозу: „<xliff:g id="EXACT_REASON">%s</xliff:g>“"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Захтевани назив датотеке је предугачак („<xliff:g id="FILENAME">%s</xliff:g>“)"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O грешка"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Нема довољно меморије. Датотека је можда превелика."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Из неочекиваног разлога није било могуће рашчланити vCard датотеку."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Формат није подржан."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Није могуће прикупити метаподатке датих vCard датотека."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Није могуће увести једну или више датотека (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Извоз датотеке <xliff:g id="FILENAME">%s</xliff:g> је завршен."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Извоз датотеке <xliff:g id="FILENAME">%s</xliff:g> је отказан"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Извоз података о контактима је у току"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Није могуће преузети информације из базе података"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Нема контаката за извоз. Ако имате контаката на телефону, неки добављачи података можда неће дозволити да се контакти извозе са телефона."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Програм за израду vCard датотека се није исправно покренуо."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Није могуће извести"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Подаци о контактима низу извезени.\nРазлог: „<xliff:g id="FAIL_REASON">%s</xliff:g>“"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Увоз <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Није могуће читати vCard податке"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Отказано је читање података са vCard датотеке"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Увоз датотеке <xliff:g id="FILENAME">%s</xliff:g> је завршен"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Увоз датотеке <xliff:g id="FILENAME">%s</xliff:g> је отказан"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Датотека <xliff:g id="FILENAME">%s</xliff:g> ће ускоро бити увезена."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Датотека ће ускоро бити увезена."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Захтев за извоз vCard датотеке је одбијен. Покушајте касније."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Датотека <xliff:g id="FILENAME">%s</xliff:g> ће ускоро бити извезена."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Захтев за извоз vCard датотеке је одбијен. Покушајте касније."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"контакт"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Кеширање vCard датотеке у локалну привремену меморију. Увоз ће ускоро започети."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Није могуће увести vCard датотеку."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Контакт преко NFC-а"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Желите ли да извезете контакте?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Кеширање..."</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Увоз <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Подешавања"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Дели видљиве контакте"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Увоз/извоз контаката"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Увоз контаката"</string>
+ <string name="share_error" msgid="948429331673358107">"Овај контакт не може да се дели."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Претрага"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Контакти за приказ"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Контакти за приказ"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Омиљено"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Нема контаката."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Обриши често контактиране"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Изаберите SIM картицу"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Увоз/извоз"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Блокирани бројеви"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"преко <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> преко <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Брисање претраге"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 265c47c..2c580a8 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Ange standard"</string>
<string name="clear_default" msgid="7193185801596678067">"Rensa standardinställningar"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Texten har kopierats"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Vill du tar bort ändringarna och sluta redigera?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Vill du ignorera ändringarna?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Ignorera"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Fortsätt redigera"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Avbryt"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Sök efter kontakter"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Ta bort kontakter"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Om"</string>
<string name="send_message" msgid="8938418965550543196">"Skicka meddelande"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"En personlig kopia skapas ..."</string>
- <string name="yesterday" msgid="6840858548955018569">"I går"</string>
<string name="tomorrow" msgid="6241969467795308581">"I morgon"</string>
<string name="today" msgid="8041090779381781781">"I dag"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"I dag kl. <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Meddelanden"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Organisera din lista"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Rensa bort dubbletter och gruppera kontakter efter etikett"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Texten har kopierats"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopiera till Urklipp"</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="8563753966926932052">"Ring"</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="5745314124619636674">"Samtal till 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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"Text"</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="3888842199855843152">"Text till 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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Rensa listan?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Listan rensas …"</string>
+ <string name="status_available" msgid="5586870015822828392">"Tillgänglig"</string>
+ <string name="status_away" msgid="1838861100379804730">"Borta"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Upptagen"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kontakter"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Övrigt"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Katalog"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Alla kontakter"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Söker …"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Mer än <xliff:g id="COUNT">%d</xliff:g> hittades."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Inga kontakter"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> hittades</item>
+ <item quantity="one">1 hittades</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Snabbkontakt för <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Inget namn)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Ofta kontaktade"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Visa kontakt"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Alla kontakter med telefonnummer"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Visa uppdateringar"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Namn"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Smeknamn"</string>
+ <string name="full_name" msgid="6602579550613988977">"Namn"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Fonetiskt namn"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetiskt mellannamn"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-post"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adress"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Chatt"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Organisation"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Relation"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Textmeddelande"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adress"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Företag"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Titel"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Anteckningar"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Webbplats"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"E-post"</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="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="map_home" msgid="1243547733423343982">"Visa hemadress"</string>
+ <string name="map_work" msgid="1360474076921878088">"Visa jobbadress"</string>
+ <string name="map_other" msgid="3817820803587012641">"Visa 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="description_minus_button" msgid="6908099247930477551">"ta bort"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Expandera eller komprimera namnfält"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Alla kontakter"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Stjärnmärkt"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Anpassa"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kontakt"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Alla andra kontakter"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Alla kontakter"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Om du tar bort <xliff:g id="GROUP">%s</xliff:g> från synkroniseringen tas även kontakter som inte tillhör grupper bort från synkroniseringen."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Sparar visningsalternativ ..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Färdig"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Avbryt"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Importera från SIM-kort"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Vill du avbryta importen av <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Vill du avbryta exporten av <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Det gick inte att avbryta importen/exporten av vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Okänt fel."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Det gick inte att öppna <xliff:g id="FILE_NAME">%s</xliff:g>: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Det gick inte att starta exportverktyget: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Det finns ingen kontakt att exportera."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Ett fel inträffade under exporten: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Det obligatoriska filnamnet är för långt (<xliff:g id="FILENAME">%s</xliff:g>)."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O-fel"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Det finns inte tillräckligt med minne. Filen kan vara för stor."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Det gick inte att analysera vCard av okänd anledning."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Formatet stöds inte."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Det gick inte att samla in metainformation för de angivna vCard-filerna."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"En eller flera filer kunde inte importeras (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> har exporterats."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Exporten av <xliff:g id="FILENAME">%s</xliff:g> avbröts."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Exporterar kontaktuppgifter"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Det gick inte att hämta databasinformation."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Det finns inga kontakter att exportera. Om du har kontakter på mobilen kanske vissa dataleverantörer inte tillåter att kontakterna exporteras från mobilen."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard-kompositören initierades inte korrekt."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Kunde inte exportera"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Kontaktuppgifterna exporterades inte.\nOrsak: <xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Importerar <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Det gick inte att läsa vCard-data"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Inläsningen av vCard-data avbröts"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard-filen <xliff:g id="FILENAME">%s</xliff:g> har importerats"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Importen av <xliff:g id="FILENAME">%s</xliff:g> avbröts"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> importeras snart."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Filen kommer snart att importeras."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Begäran om vCard-import avvisades. Försök igen vid ett senare tillfälle."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> exporteras snart."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Begäran om vCard-export avvisades. Försök igen vid ett senare tillfälle."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kontakt"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard-fil(er) cachelagras till en lokal tillfällig lagringsenhet. Den faktiska importen börjar snart."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Det gick inte att importera vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Mott. v. NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Exportera kontakter?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Cachelagrar ..."</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Importerar <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Inställningar"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Dela synliga kontakter"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Importera/exportera kontakter"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Importera kontakter"</string>
+ <string name="share_error" msgid="948429331673358107">"Den här kontakten kan inte delas."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Sök"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Kontakter som ska visas"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Kontakter som ska visas"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Favoriter"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Inga kontakter."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Rensa listan över kontakter"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Välj SIM-kort"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Importera/exportera"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Blockerade nummer"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"via <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> via <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Rensa sökning"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 4dd493d..6281426 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Weka chaguo-msingi"</string>
<string name="clear_default" msgid="7193185801596678067">"Ondoa chaguo-msingi"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Maandishi yamenakiliwa"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Je, ungependa kutupa mabadiliko yako na uache kubadilisha?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Je, unataka kutupa mabadiliko?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Tupa"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Endelea kubadilisha"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Ghairi"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Tafuta anwani"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Ondoa anwani"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Kuhusu"</string>
<string name="send_message" msgid="8938418965550543196">"Tuma ujumbe"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Inaunda nakala ya kibinafsi..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Jana"</string>
<string name="tomorrow" msgid="6241969467795308581">"Kesho"</string>
<string name="today" msgid="8041090779381781781">"Leo"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Leo saa <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Ujumbe"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Panga orodha yako"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Ondoa zilizorudiwa na upange anwani kulingana na lebo"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Maandishi yamenakiliwa"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Nakili kwenye ubao wa kunakili"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Mpigie <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Piga simu nyumbani"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Pigia simu ya mkononi"</string>
+ <string name="call_work" msgid="5328785911463744028">"Piga simu kazini"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Piga simu kwa pepesi ya kazini"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Piga simu kwa pepesi ya nyumbani"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Piga simu kwa peja"</string>
+ <string name="call_other" msgid="8563753966926932052">"Piga simu"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Mpigie"</string>
+ <string name="call_car" msgid="3280537320306436445">"Piga simu kwa gari"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Pigia nambari kuu ya simu ya kampuni"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Piga simu kwa ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Piga simu kuu"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Piga simu ya faksi"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Piga simu kwa redio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Piga simu kwa telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Pigia TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Piga simu kwa simu ya mkononi ya kazini"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Piga simu kwa peja"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Piga simu <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Piga simu kwa MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Tuma ujumbe kwa <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Tuma ujumbe kwa simu ya nyumbani"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Tuma ujumbe wa maandishi kwa simu ya mkononi"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Tuma ujumbe kazini"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Tuma maandishi kwa faksi ya kazini"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Tuma ujumbe kwa pepesi ya nyumbani"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Tuma ujumbe kwa peja"</string>
+ <string name="sms_other" msgid="806127844607642331">"Matini"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Piga simu tena kwa kutumia maandishi"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Tuma ujumbe kwa gari"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Kampuni kuu ya maandishi"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Tuma ujumbe kwa ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Tuma ujumbe wa simu kuu"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Faksi ya maandishi"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Tuma ujumbe kwa redio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Tuma ujumbe kwa teleksi"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Tuma ujumbe kwa TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Tuma ujumbe kwa simu ya mkononi ya kazini"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Tuma ujumbe kwa peja ya kazini"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Tuma ujumbe kwa <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Tuma maandishi ya MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Futa uliowasiliana nao mara kwa mara?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Inafuta uliowasiliana nao mara kwa mara..."</string>
+ <string name="status_available" msgid="5586870015822828392">"Nipo"</string>
+ <string name="status_away" msgid="1838861100379804730">"Mbali"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Ana shughuli"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Anwani"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Nyingineyo"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Saraka"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Anwani zote"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Inatafuta…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"zaidi ya <xliff:g id="COUNT">%d</xliff:g> zimepatikana."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Hakuna anwani"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> zimepatikana</item>
+ <item quantity="one">Moja imepatikana</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Mwasiliani wa haraka wa <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Hakuna jina)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Unaowasiliana nao zaidi"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Angalia anwani"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Anwani zote zilizo na nambari za simu"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Tazama masasisho"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Jina"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Jina la utani"</string>
+ <string name="full_name" msgid="6602579550613988977">"Jina"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Herufi za kwanza za jina"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Jina la kati"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Herufi za mwisho za jina"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Jina la kifonetiki"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Jina la katikati la kifonetiki"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Simu"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Barua pepe"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Anwani"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Ujumbe wa Papo Hapo"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Shirika"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Uhusiano"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Ujumbe wa maandishi"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Anwani"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Kampuni"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Jina la heshima"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Hati"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Tovuti"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Nyumbani mwa barua pepe"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Tuma barua pepe kwa simu ya mkononi"</string>
+ <string name="email_work" msgid="2807430017302722689">"Tuma barua pepe kazini"</string>
+ <string name="email_other" msgid="3454004077967657109">"Barua pepe"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Barua pepe <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Barua pepe"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Barabara"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Sanduku la posta"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Mtaa"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Jiji"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Jimbo"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Msimbo wa posta"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Nchi"</string>
+ <string name="map_home" msgid="1243547733423343982">"Angalia anwani ya nyumbani"</string>
+ <string name="map_work" msgid="1360474076921878088">"Angalia anwani ya kazini"</string>
+ <string name="map_other" msgid="3817820803587012641">"Tazama anwani"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Angalia anwani <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Piga gumzo kwa kutumia AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Piga gumzo kwa kutumia Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Piga gumzo kwa kutumia Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Piga gumzo kwa kutumia Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Piga gumzo kwa kutumia QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Piga gumzo kwa kutumia Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Piga gumzo kwa kutumia ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Piga gumzo kwa kutumia Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Gumzo"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"futa"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Panua au ukunje sehemu za jina"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Anwani zote"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Zenye Nyota"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Badilisha kukufaa"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Anwani"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Anwani Zingine Zote"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Wawasiliani wote"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Ondoa kikundi cha usawazishaji"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Ongeza kikundi cha usawazishaji"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Vikundi zaidi..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Kuondoa \"<xliff:g id="GROUP">%s</xliff:g>\" \"kutoka usawazishaji pia kutaondoa anwani zisizo katika kikundi kwenye usawazishaji."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Inahifadhi chaguo za mwonyesho.."</string>
+ <string name="menu_done" msgid="796017761764190697">"Kwisha"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Ghairi"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Ingiza kutoka kwa SIM kadi"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Ghairi kuletwa kwa <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Ghairi kuhamishwa kwa <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Haikuweza kughairi kuingiza/kuhamisha vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Hitilafu isiyojulikana."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Haikuweza kufungua \"{<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Haikuweza kuanzisha kihamishaji: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Hakuna anwani inayoweza kuhamishwa."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Hitilafu imetokea wakati wa uhamisho: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Jina la faili linalohitajika ni refu sana (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Hitilafu ya I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Hakuna kumbukumbu ya kutosha. Faili inaweza kuwa kubwa mno."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Haikuweza kuchanganua vCard kwa sababu isiyotarajiwa."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Fomati haiauniwi"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Haikuweza kukusanya maelezo meta ya faili zilizopeanwa za vCard."</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Imemaliza kuhamisha <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Kuhamisha <xliff:g id="FILENAME">%s</xliff:g> kumeghairiwa"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Inahamisha data ya anwani"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Haikupata maelezo ya hifadhidata."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Hakuna anwani za kuhamishwa. Kama una anwani kwenye simu yako, baadhi ya wahudumu wa data wanaweza kosa kuruhusu anwani kuhamishwa kutoka kwa simu."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Kitunzi cha vCard hakikuanza vizuri."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Imeshindwa kuhamisha"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Data ya mwasiliani haikuhamishwa.\nSababu: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Inaingiza <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Haikuweza kusoma data ya vKadi"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Kusoma data ya VCard kumeghairiwa"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Imemaliza kuingiza vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Kuingiza <xliff:g id="FILENAME">%s</xliff:g> kumeghairiwa"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> italetwa hivi karibuni."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Faili italetwa hivi karibuni."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Ombi la kuleta vCard limekataliwa. Tafadhali jaribu baadaye."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> itahamishwa hivi karibuni."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Ombi la kuhamishwa kwa vCard limekataliwa. Jaribu tena baadaye."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"anwani"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Vcard Inaakibisha ndani ya hifadhi ya muda mfupi. Uhamisho halisi utaanza hivi karibuni."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Haikuweza kuingiza vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Anwani imepokewa kupitia NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Hamisha anwani?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Inaakibisha..."</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Inaingiza <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Mipangilio"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Shiriki anwani zinazoonekana"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Leta/Hamisha wawasiliani"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Ingiza anwani"</string>
+ <string name="share_error" msgid="948429331673358107">"Mwasiliani huyu hawezi kushirikishwa."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Tafuta"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Anwani za kuonyesha"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Anwani za uonyesha"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Vipendwa"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Hakuna wawasiliani."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Futa idadi ya mara ambazo unawasiliana nao"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Chagua SIM kadi"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Leta/hamisha"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Nambari zilizozuiwa"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"kupitia <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> kupitia <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Futa utafutaji"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-sw600dp-land/integers.xml b/res/values-sw600dp-land/integers.xml
index 1785443..b6fe15a 100644
--- a/res/values-sw600dp-land/integers.xml
+++ b/res/values-sw600dp-land/integers.xml
@@ -26,4 +26,9 @@
<!-- Top margin ratio for the image for empty account view -->
<integer name="empty_account_view_image_margin_divisor">5</integer>
+
+ <integer name="contact_tile_column_count_in_favorites">3</integer>
+
+ <!-- The number of characters in the snippet before we need to tokenize and ellipse. -->
+ <integer name="snippet_length_before_tokenize">20</integer>
</resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 6e4f808..6f6f4e1 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -59,4 +59,22 @@
<!-- Margin offset b/w the image top and app bar bottom for no account empty view -->
<dimen name="contacts_no_account_empty_image_offset">238dp</dimen>
+
+ <dimen name="detail_item_side_margin">0dip</dimen>
+
+ <dimen name="contact_browser_list_header_left_margin">@dimen/list_visible_scrollbar_padding</dimen>
+ <dimen name="contact_browser_list_header_right_margin">24dip</dimen>
+ <dimen name="contact_browser_list_top_margin">16dip</dimen>
+
+ <!-- End margin of the account filter header icon -->
+ <dimen name="contact_browser_list_header_icon_right_margin">22dp</dimen>
+ <dimen name="contact_browser_list_header_icon_right_margin_alt">24dp</dimen>
+
+ <dimen name="contact_filter_list_item_padding_start">24dp</dimen>
+ <dimen name="contact_filter_left_margin">16dp</dimen>
+
+ <!-- Right margin of the floating action button -->
+ <dimen name="floating_action_button_margin_right">32dp</dimen>
+ <!-- Bottom margin of the floating action button -->
+ <dimen name="floating_action_button_margin_bottom">32dp</dimen>
</resources>
diff --git a/res/values-sw600dp/integers.xml b/res/values-sw600dp/integers.xml
index 4eb0061..4b2d73f 100644
--- a/res/values-sw600dp/integers.xml
+++ b/res/values-sw600dp/integers.xml
@@ -3,4 +3,11 @@
<resources>
<!-- Top margin ratio for the image for empty group view -->
<integer name="empty_group_view_image_margin_divisor">4</integer>
-</resources>
\ No newline at end of file
+
+ <integer name="contact_tile_column_count_in_favorites">3</integer>
+
+ <!-- The number of characters in the snippet before we need to tokenize and ellipse. -->
+ <!-- Yikes, there is less space on a tablet! This makes the search experience rather
+ poor. Another reason to get rid of the exist tablet layout. -->
+ <integer name="snippet_length_before_tokenize">15</integer>
+</resources>
diff --git a/res/values-sw600dp/strings.xml b/res/values-sw600dp/strings.xml
new file mode 100644
index 0000000..c9946f9
--- /dev/null
+++ b/res/values-sw600dp/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2012 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- 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. [CHAR LIMIT=20] -->
+ <string name="account_phone">Device</string>
+
+ <!-- This error message shown when the user actually have no contact
+ (e.g. just after data-wiping), or, data providers of the contact list prohibits their
+ contacts from being exported to outside world via vcard exporter, etc. [CHAR LIMIT=NONE] -->
+ <string name="composer_has_no_exportable_contact">There are no exportable contacts. If you do have contacts on your tablet, some data providers may not allow the contacts to be exported from the tablet.</string>
+
+</resources>
diff --git a/res/values-sw720dp-land/integers.xml b/res/values-sw720dp-land/integers.xml
new file mode 100644
index 0000000..a83cdff
--- /dev/null
+++ b/res/values-sw720dp-land/integers.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012 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>
+ <integer name="contact_tile_column_count_in_favorites">4</integer>
+
+ <!-- The number of characters in the snippet before we need to tokenize and ellipse. -->
+ <integer name="snippet_length_before_tokenize">30</integer>
+</resources>
diff --git a/res/values-sw720dp/integers.xml b/res/values-sw720dp/integers.xml
index 1cc510e..93bbc68 100644
--- a/res/values-sw720dp/integers.xml
+++ b/res/values-sw720dp/integers.xml
@@ -20,4 +20,9 @@
<!-- Layout weight of the content column for tile favorites list, all contacts list, and
QuickContact -->
<integer name="contact_list_card_layout_weight">81</integer>
+
+ <integer name="contact_tile_column_count_in_favorites">2</integer>
+
+ <!-- The number of characters in the snippet before we need to tokenize and ellipse. -->
+ <integer name="snippet_length_before_tokenize">20</integer>
</resources>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index 54a3f68..182006b 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"இயல்புநிலையாக அமை"</string>
<string name="clear_default" msgid="7193185801596678067">"இயல்பை அழி"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"உரை நகலெடுக்கப்பட்டது"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"மாற்றங்களை நிராகரித்து, திருத்துவதிலிருந்து வெளியேறவா?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"மாற்றங்களை நிராகரிக்கவா?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"நிராகரி"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"தொடர்ந்து திருத்து"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"ரத்துசெய்"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"தொடர்புகளில் தேடுக"</string>
<string name="title_edit_group" msgid="8602752287270586734">"தொடர்புகளை அகற்று"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"அறிமுகம்"</string>
<string name="send_message" msgid="8938418965550543196">"செய்தி அனுப்பு"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"தனிப்பட்ட நகலை உருவாக்குகிறது…"</string>
- <string name="yesterday" msgid="6840858548955018569">"நேற்று"</string>
<string name="tomorrow" msgid="6241969467795308581">"நாளை"</string>
<string name="today" msgid="8041090779381781781">"இன்று"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"இன்று <xliff:g id="TIME_INTERVAL">%s</xliff:g> மணிக்கு"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"செய்திகள்"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"உங்கள் பட்டியலை ஒழுங்கமைக்கவும்"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"நகல்களை நீக்கலாம் & லேபிளின்படி தொடர்புகளைக் குழுவாக்கலாம்"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"உரை நகலெடுக்கப்பட்டது"</string>
+ <string name="copy_text" msgid="3257145021583508761">"கிளிப்போர்டுக்கு நகலெடு"</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="8563753966926932052">"அழை"</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="5745314124619636674">"தொலைநகல் எண்ணில் அழை"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"உரை"</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="3888842199855843152">"தொலைநகல் எண்ணிற்கு உரைச்செய்தி அனுப்பு"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"அடிக்கடி தொடர்புகொண்ட தொடர்பை அழிக்கவா?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"அடிக்கடித் தொடர்புகொண்ட தொடர்பை அழிக்கிறது…"</string>
+ <string name="status_available" msgid="5586870015822828392">"இருக்கிறார்"</string>
+ <string name="status_away" msgid="1838861100379804730">"வெளியே"</string>
+ <string name="status_busy" msgid="9147992455450257136">"பணிமிகுதி"</string>
+ <string name="contactsList" msgid="8661624236494819731">"தொடர்புகள்"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"மற்றவை"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"கோப்பகம்"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"எல்லா தொடர்புகளும்"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"தேடுகிறது..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g> க்கும் மேற்பட்டவை கண்டறியப்பட்டன."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"தொடர்புகள் எதுவும் இல்லை"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> கண்டறியப்பட்டன</item>
+ <item quantity="one">1 கண்டறியப்பட்டது</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> க்கான உடனடித் தொடர்பு"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(பெயர் இல்லை)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"அடிக்கடி தொடர்புகொண்டவர்கள்"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"தொடர்பைக் காட்டு"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"மொபைல் எண்களுடனான எல்லா தொடர்புகளும்"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"புதுப்பிப்புகளைக் காட்டு"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"பெயர்"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"செல்லப்பெயர்"</string>
+ <string name="full_name" msgid="6602579550613988977">"பெயர்"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"பெயரின் ஒலிப்புமுறை"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"ஒலிப்புமுறையில் பெயரின் நடுப்பகுதி"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"மொபைல்"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"மின்னஞ்சல்"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"முகவரி"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"நிறுவனம்"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"உறவு"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"உரைச் செய்தி"</string>
+ <string name="postal_address" msgid="8765560217149624536">"முகவரி"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"நிறுவனம்"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"தலைப்பு"</string>
+ <string name="label_notes" msgid="8337354953278341042">"குறிப்புகள்"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"இணையதளம்"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"மின்னஞ்சல்"</string>
+ <string name="email_custom" msgid="7548003991586214105">"<xliff:g id="CUSTOM">%s</xliff:g> க்கு மின்னஞ்சல் அனுப்பு"</string>
+ <string name="email" msgid="5668400997660065897">"மின்னஞ்சல்"</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="map_home" msgid="1243547733423343982">"வீட்டு முகவரியைக் காட்டு"</string>
+ <string name="map_work" msgid="1360474076921878088">"பணியிட முகவரியைக் காட்டு"</string>
+ <string name="map_other" msgid="3817820803587012641">"முகவரியைக் காட்டு"</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="description_minus_button" msgid="6908099247930477551">"நீக்கு"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"பெயர் புலங்களை விரிவுப்படுத்து அல்லது சுருக்கு"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"எல்லா தொடர்புகளும்"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"நட்சத்திரமிட்டவை"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"தனிப்பயனாக்கு"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"தொடர்பு"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"பிற எல்லா தொடர்புகளும்"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"எல்லா தொடர்புகளும்"</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_warn_remove_ungrouped" msgid="8872290721676651414">"ஒத்திசைவிலிருந்து \"<xliff:g id="GROUP">%s</xliff:g>\" ஐ அகற்றுவது, ஒத்திசைவிலிருந்து குழுவாக்கப்படாத எல்லா தொடர்புகளையும் அகற்றும்."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"காட்சி விருப்பங்களைச் சேமிக்கிறது…"</string>
+ <string name="menu_done" msgid="796017761764190697">"முடிந்தது"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"ரத்துசெய்"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"சிம் கார்டிலிருந்து இறக்குமதிசெய்"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> இன் இறக்குமதியை ரத்துசெய்யவா?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> இன் ஏற்றுமதியை ரத்துசெய்யவா?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard இன் இறக்குமதி/ஏற்றுமதியை ரத்துசெய்ய முடியவில்லை"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"தெரியாத பிழை."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" ஐத் திறக்க முடியவில்லை: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"ஏற்றுமதியைத் தொடங்க முடியவில்லை: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"ஏற்றுமதி செய்யக்கூடிய தொடர்பு இல்லை."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"ஏற்றுமதி செய்யும்போது பிழை: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"தேவையான கோப்பின் பெயர் மிகவும் நீளமாக உள்ளது (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O பிழை"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"போதுமான நினைவகம் இல்லை. கோப்பு மிகவும் பெரியதாக இருக்கலாம்."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"எதிர்பாராதவிதமாக vCard ஐப் பாகுபடுத்த முடியவில்லை."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"வடிவம் ஆதரிக்கப்படவில்லை."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"வழங்கப்பட்ட vCard கோப்பின்(களின்) மெட்டா தகவலைச் சேகரிக்க முடியவில்லை."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"ஒன்று அல்லது அதற்கு மேற்பட்ட கோப்புகளை ஏற்றுமதி செய்ய முடியவில்லை (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> ஐ ஏற்றுமதி செய்வது முடிந்தது."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> ஐ ஏற்றுமதி செய்வது ரத்துசெய்யப்பட்டது."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"தொடர்பு தரவை ஏற்றுமதி செய்கிறது"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"தரவுத்தளத் தகவலைப் பெற முடியவில்லை."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"ஏற்றுமதி செய்யத்தக்க தொடர்புகள் இல்லை. மொபைலில் தொடர்புகள் இல்லை எனில், மொபைலிலிருந்து தொடர்புகளை ஏற்றுமதி செய்வதற்குச் சில தரவு வழங்குநர்கள் அனுமதிக்காமல் போகலாம்."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard தொகுப்பான் முறையாகத் தொடங்கவில்லை."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"ஏற்றுமதி செய்ய முடியவில்லை"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"தொடர்பு தரவு ஏற்றுமதி செய்யப்படவில்லை.\nகாரணம்: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> ஐ இறக்குமதி செய்கிறது"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard தரவைப் படிக்க முடியவில்லை"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard தரவைப் படிப்பது ரத்துசெய்யப்பட்டது"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g> ஐ இறக்குமதிசெய்வது முடிந்தது"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> ஐ இறக்குமதிசெய்வது ரத்துசெய்யப்பட்டது"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> விரைவில் இறக்குமதி செய்யப்படும்."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"கோப்பு விரைவில் இறக்குமதி செய்யப்படும்."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard இன் இறக்குமதி கோரிக்கை நிராகரிக்கப்பட்டது. பிறகு முயற்சிக்கவும்."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> விரைவில் ஏற்றுமதி செய்யப்படும்."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard இன் ஏற்றுமதி கோரிக்கை நிராகரிக்கப்பட்டது. பிறகு முயற்சிக்கவும்."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"தொடர்பு"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard(களை) ஐ அகச் சேமிப்பிடத்தில் தற்காலிகமாகச் சேமிக்கிறது. அசல் இறக்குமதி உடனடியாக தொடங்கப்படும்."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard ஐ இறக்குமதி செய்ய முடியவில்லை."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC வழியாக தொடர்பு பெறப்பட்டது"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"தொடர்புகளை ஏற்றுமதி செய்யவா?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"தற்காலிகமாகச் சேமித்தல்"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g> ஐ இறக்குமதி செய்கிறது: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"அமைப்பு"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"தெரியும் தொடர்புகளைப் பகிர்க"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"தொடர்புகளை இறக்குமதி/ஏற்றுமதி செய்தல்"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"தொடர்புகளை இறக்குமதி செய்"</string>
+ <string name="share_error" msgid="948429331673358107">"தொடர்பைப் பகிர முடியவில்லை."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"தேடு"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"காட்ட வேண்டிய தொடர்புகள்"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"காட்டுவதற்கான தொடர்புகள்"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"விருப்பமானவை"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"தொடர்புகள் இல்லை."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"அடிக்கடி தொடர்புகொண்டவர்களை அழி"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"சிம் ஐத் தேர்ந்தெடுக்கவும்"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"இறக்குமதி/ஏற்றுமதி"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"தடுக்கப்பட்ட எண்கள்"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g> வழியாக"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="SOURCE">%2$s</xliff:g> வழியாக <xliff:g id="DATE">%1$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"தேடலை அழி"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index 21fcf0c..1978f4c 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"డిఫాల్ట్గా సెట్ చేయి"</string>
<string name="clear_default" msgid="7193185801596678067">"డిఫాల్ట్ను క్లియర్ చేయి"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"వచనం కాపీ చేయబడింది"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"మీ మార్పులను విస్మరించి, సవరణ నుండి నిష్క్రమించాలా?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"మార్పులను విస్మరించాలా?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"విస్మరించు"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"సవరణను కొనసాగించు"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"రద్దు చేయి"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"పరిచయాలను శోధించండి"</string>
<string name="title_edit_group" msgid="8602752287270586734">"పరిచయాలను తీసివేయండి"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"పరిచయం"</string>
<string name="send_message" msgid="8938418965550543196">"సందేశాన్ని పంపండి"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"వ్యక్తిగత కాపీని సృష్టిస్తోంది..."</string>
- <string name="yesterday" msgid="6840858548955018569">"నిన్న"</string>
<string name="tomorrow" msgid="6241969467795308581">"రేపు"</string>
<string name="today" msgid="8041090779381781781">"ఈ రోజు"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"ఈ రోజు <xliff:g id="TIME_INTERVAL">%s</xliff:g>కి"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"సందేశాలు"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"మీ జాబితాను ఉత్తమంగా నిర్వహించండి"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"నకిలీలను తొలగించండి & పరిచయాలను లేబుల్ వారీగా వర్గీకరించండి"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"వచనం కాపీ చేయబడింది"</string>
+ <string name="copy_text" msgid="3257145021583508761">"క్లిప్బోర్డ్కు కాపీ చేయి"</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="8563753966926932052">"కాల్ చేయండి"</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="5745314124619636674">"ఫ్యాక్స్కి కాల్ చేయండి"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"వచనం పంపండి"</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="3888842199855843152">"ఫ్యాక్స్కు వచనం పంపండి"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"తరచుగా సంప్రదించినవాటిని క్లియర్ చేయాలా?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"తరచుగా సంప్రదించినవాటిని క్లియర్ చేస్తోంది…"</string>
+ <string name="status_available" msgid="5586870015822828392">"అందుబాటులో ఉన్నారు"</string>
+ <string name="status_away" msgid="1838861100379804730">"దూరంగా ఉన్నారు"</string>
+ <string name="status_busy" msgid="9147992455450257136">"బిజీగా ఉన్నారు"</string>
+ <string name="contactsList" msgid="8661624236494819731">"పరిచయాలు"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"ఇతరం"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"డైరెక్టరీ"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"అన్ని పరిచయాలు"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"శోధిస్తోంది..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g> కంటే ఎక్కువ కనుగొనబడ్డాయి."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"పరిచయాలు లేవు"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> కనుగొనబడ్డాయి</item>
+ <item quantity="one">1 కనుగొనబడింది</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> కోసం త్వరిత సంప్రదింపు"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(పేరు లేదు)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"తరచుగా సంప్రదించబడినవి"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"పరిచయాన్ని వీక్షించండి"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"ఫోన్ నంబర్లు గల అన్ని పరిచయాలు"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"తాజా విషయాలను వీక్షించండి"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"పేరు"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"మారుపేరు"</string>
+ <string name="full_name" msgid="6602579550613988977">"పేరు"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"ఫోనెటిక్ రూపంలో పేరు"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"ఫోనెటిక్ రూపంలో మధ్య పేరు"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"ఫోన్"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"ఇమెయిల్"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"చిరునామా"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"సంస్థ"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"సంబంధం"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"వచన సందేశం"</string>
+ <string name="postal_address" msgid="8765560217149624536">"చిరునామా"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"కంపెనీ"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"శీర్షిక"</string>
+ <string name="label_notes" msgid="8337354953278341042">"గమనికలు"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"వెబ్సైట్"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"ఇమెయిల్ చేయండి"</string>
+ <string name="email_custom" msgid="7548003991586214105">"<xliff:g id="CUSTOM">%s</xliff:g>కు ఇమెయిల్ చేయండి"</string>
+ <string name="email" msgid="5668400997660065897">"ఇమెయిల్ చేయండి"</string>
+ <string name="postal_street" msgid="8133143961580058972">"వీధి"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO పెట్టె"</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="map_home" msgid="1243547733423343982">"ఇంటి చిరునామాను వీక్షించండి"</string>
+ <string name="map_work" msgid="1360474076921878088">"కార్యాలయ చిరునామాను వీక్షించండి"</string>
+ <string name="map_other" msgid="3817820803587012641">"చిరునామాను వీక్షించండి"</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="description_minus_button" msgid="6908099247930477551">"తొలగించు"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"పేరు ఫీల్డ్లను విస్తరింపజేయి లేదా కుదించు"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"అన్ని పరిచయాలు"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"నక్షత్రం గుర్తు ఉన్నవి"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"అనుకూలీకరించు"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"పరిచయం"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"అన్ని ఇతర పరిచయాలు"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"అన్ని పరిచయాలు"</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_warn_remove_ungrouped" msgid="8872290721676651414">"సమకాలీకరణ నుండి \"<xliff:g id="GROUP">%s</xliff:g>\"ని తీసివేయడం వలన సమకాలీకరణ నుండి సమూహం చేయబడని పరిచయాలు కూడా తీసివేయబడతాయి."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"ప్రదర్శన ఎంపికలను సేవ్ చేస్తోంది…"</string>
+ <string name="menu_done" msgid="796017761764190697">"పూర్తయింది"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"రద్దు చేయి"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM కార్డు నుండి దిగుమతి చేయండి"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> యొక్క దిగుమతిని రద్దు చేయాలా?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> యొక్క ఎగుమతిని రద్దు చేయాలా?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard దిగుమతి/ఎగుమతిని రద్దు చేయడం సాధ్యపడలేదు"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"తెలియని లోపం."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\"ని తెరవడం సాధ్యపడలేదు: <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"ఎక్స్పోర్టర్ను ప్రారంభించడం సాధ్యపడలేదు: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"ఎగమతి చేయగల పరిచయం లేదు."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"ఎగుమతి సమయంలో లోపం సంభవించింది: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"అవసరమైన ఫైల్ పేరు (\"<xliff:g id="FILENAME">%s</xliff:g>\") చాలా పెద్దదిగా ఉంది."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O లోపం"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"తగినంత మెమరీ లేదు. ఫైల్ చాలా పెద్దదిగా ఉండవచ్చు."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"ఊహించని కారణంగా vCardను అన్వయించడం సాధ్యపడలేదు."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"ఆకృతికి మద్దతు లేదు."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"అందించిన vCard ఫైల్(లు) యొక్క మెటా డేటా సమాచారాన్ని సేకరించడం సాధ్యపడలేదు."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"ఒకటి లేదా అంతకంటే ఎక్కువ ఫైల్లను (%s) దిగుమతి చేయడం సాధ్యపడలేదు."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g>ని ఎగుమతి చేయడం పూర్తయింది."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g>ని ఎగుమతి చేయడం రద్దు చేయబడింది."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"పరిచయ డేటాను ఎగుమతి చేస్తోంది"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"డేటాబేస్ సమాచారాన్ని పొందడం సాధ్యపడలేదు."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"ఎగుమతి చేయదగిన పరిచయాలు ఏవీ లేవు. మీరు మీ ఫోన్లో పరిచయాలు కలిగి ఉన్నప్పటికీ, కొందరు డేటా ప్రదాతలు పరిచయాలను ఫోన్ నుండి ఎగుమతి చేయడానికి అనుమతించకపోవచ్చు."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard కంపోజర్ సరిగ్గా ప్రారంభించబడలేదు."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"ఎగుమతి చేయడం సాధ్యపడలేదు"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"పరిచయ డేటా ఎగుమతి చేయబడలేదు.\nకారణం: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g>ని దిగుమతి చేస్తోంది"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard డేటాను చదవడం సాధ్యపడలేదు"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard డేటాను చదవడం రద్దు చేయబడింది"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g>ని దిగుమతి చేయడం పూర్తయింది"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g>ని దిగుమతి చేయడం రద్దు చేయబడింది"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> కొద్దిసేపట్లో దిగుమతి చేయబడుతుంది."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"ఫైల్ కొద్దిసేపట్లో దిగుమతి చేయబడుతుంది."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard దిగుమతి అభ్యర్థన తిరస్కరించబడింది. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> కొద్దిసేపట్లో ఎగుమతి చేయబడుతుంది."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard ఎగుమతి అభ్యర్థన తిరస్కరించబడింది. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"పరిచయం"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard(ల)ను స్థానిక తాత్కాలిక నిల్వకు కాష్ చేస్తోంది. అసలు దిగుమతి కొద్దిసేపట్లో ప్రారంభమవుతుంది."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCardని దిగుమతి చేయడం సాధ్యపడలేదు."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"పరిచయం NFC ద్వారా స్వీకరించబడింది"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"పరిచయాలను ఎగుమతి చేయాలా?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"కాష్ చేస్తోంది"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="TOTAL_NUMBER">%s</xliff:g>లో <xliff:g id="CURRENT_NUMBER">%s</xliff:g> దిగుమతి చేయబడుతోంది: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"సెట్టింగ్లు"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"కనిపించే పరిచయాలను భాగస్వామ్యం చేయండి"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"పరిచయాలను దిగుమతి/ఎగుమతి చేయండి"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"పరిచయాలను దిగుమతి చేయండి"</string>
+ <string name="share_error" msgid="948429331673358107">"ఈ పరిచయాన్ని భాగస్వామ్యం చేయడం సాధ్యపడదు."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"శోధించు"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"ప్రదర్శించాల్సిన పరిచయాలు"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"ప్రదర్శించాల్సిన పరిచయాలు"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"ఇష్టమైనవి"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"పరిచయాలు లేవు."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"తరచుగా ఉన్నవాటిని క్లియర్ చేయి"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM కార్డును ఎంచుకోండి"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"దిగుమతి చేయి/ఎగుమతి చేయి"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"బ్లాక్ చేయబడిన నంబర్లు"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g> ద్వారా"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="SOURCE">%2$s</xliff:g> ద్వారా <xliff:g id="DATE">%1$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"శోధనను క్లియర్ చేయి"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index c55f8ce..d4d87b3 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"ตั้งเป็นค่าเริ่มต้น"</string>
<string name="clear_default" msgid="7193185801596678067">"ล้างจากค่าเริ่มต้น"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"คัดลอกข้อความแล้ว"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"ยกเลิกการเปลี่ยนแปลงและออกจากการแก้ไขใช่ไหม"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"ยกเลิกการเปลี่ยนแปลงหรือไม่"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"ยกเลิก"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"แก้ไขต่อ"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"ยกเลิก"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"ค้นหารายชื่อติดต่อ"</string>
<string name="title_edit_group" msgid="8602752287270586734">"นำรายชื่อติดต่อออก"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"เกี่ยวกับ"</string>
<string name="send_message" msgid="8938418965550543196">"ส่งข้อความ"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"กำลังสร้างสำเนาส่วนบุคคล..."</string>
- <string name="yesterday" msgid="6840858548955018569">"เมื่อวานนี้"</string>
<string name="tomorrow" msgid="6241969467795308581">"พรุ่งนี้"</string>
<string name="today" msgid="8041090779381781781">"วันนี้"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"วันนี้เวลา <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"ข้อความ"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"จัดระเบียบรายชื่อ"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"ลบรายชื่อซ้ำและจัดกลุ่มตามป้ายกำกับ"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"คัดลอกข้อความแล้ว"</string>
+ <string name="copy_text" msgid="3257145021583508761">"คัดลอกไปยังคลิปบอร์ด"</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="8563753966926932052">"โทร"</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="5745314124619636674">"โทรเข้าหมายเลขแฟกซ์"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"ข้อความ"</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="3888842199855843152">"ส่งข้อความถึงหมายเลขแฟกซ์"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"ล้างผู้ที่คุณติดต่อด้วยบ่อยๆ หรือไม่"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"กำลังล้างผู้ที่คุณติดต่อด้วยบ่อยๆ…"</string>
+ <string name="status_available" msgid="5586870015822828392">"ว่าง"</string>
+ <string name="status_away" msgid="1838861100379804730">"ไม่อยู่"</string>
+ <string name="status_busy" msgid="9147992455450257136">"ไม่ว่าง"</string>
+ <string name="contactsList" msgid="8661624236494819731">"รายชื่อในสมุดโทรศัพท์"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"อื่นๆ"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"ไดเรกทอรี"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"รายชื่อติดต่อทั้งหมด"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"กำลังค้นหา..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"พบมากกว่า <xliff:g id="COUNT">%d</xliff:g> รายการ"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"ไม่มีรายชื่อติดต่อ"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">พบ <xliff:g id="COUNT">%d</xliff:g> รายการ</item>
+ <item quantity="one">พบ 1 รายการ</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"สมุดโทรศัพท์ด่วนสำหรับ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(ไม่มีชื่อ)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"ที่ติดต่อบ่อยครั้ง"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"ดูรายชื่อติดต่อ"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"รายชื่อติดต่อทั้งหมดที่มีหมายเลขโทรศัพท์"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"ดูการอัปเดต"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"ชื่อ"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"ชื่อเล่น"</string>
+ <string name="full_name" msgid="6602579550613988977">"ชื่อ"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"ชื่อแบบออกเสียง"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"ชื่อกลางแบบออกเสียง"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"โทรศัพท์"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"อีเมล"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"ที่อยู่"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"องค์กร"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"ความสัมพันธ์"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"ข้อความตัวอักษร"</string>
+ <string name="postal_address" msgid="8765560217149624536">"ที่อยู่"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"บริษัท"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"ชื่อ"</string>
+ <string name="label_notes" msgid="8337354953278341042">"หมายเหตุ"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"เว็บไซต์"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"อีเมล"</string>
+ <string name="email_custom" msgid="7548003991586214105">"อีเมล <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"อีเมล"</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="map_home" msgid="1243547733423343982">"ดูที่อยู่บ้าน"</string>
+ <string name="map_work" msgid="1360474076921878088">"ดูที่อยู่ที่ทำงาน"</string>
+ <string name="map_other" msgid="3817820803587012641">"ดูที่อยู่"</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="description_minus_button" msgid="6908099247930477551">"ลบ"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"ขยายหรือยุบฟิลด์ชื่อ"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"รายชื่อติดต่อทั้งหมด"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"ที่ติดดาว"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"กำหนดค่า"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"รายชื่อติดต่อ"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"รายชื่อติดต่ออื่นทั้งหมด"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"รายชื่อติดต่อทั้งหมด"</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_warn_remove_ungrouped" msgid="8872290721676651414">"การนำ \"<xliff:g id="GROUP">%s</xliff:g>\" ออกจากการซิงค์จะนำรายชื่อติดต่อที่ไม่ได้จัดกลุ่มไว้ออกจากการซิงค์ด้วย"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"บันทึกตัวเลือกการแสดงผล..."</string>
+ <string name="menu_done" msgid="796017761764190697">"เสร็จสิ้น"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"ยกเลิก"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"นำเข้าจากซิมการ์ด"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"ยกเลิกการนำเข้า <xliff:g id="FILENAME">%s</xliff:g> หรือไม่"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"ยกเลิกการส่งออก <xliff:g id="FILENAME">%s</xliff:g> หรือไม่"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"ไม่สามารถยกเลิกการนำเข้า/ส่งออก vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"ข้อผิดพลาดที่ไม่รู้จัก"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"ไม่สามารถเปิด \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"เริ่มใช้งานโปรแกรมส่งออกไม่ได้: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"ไม่มีรายชื่อติดต่อที่สามารถส่งออกได้"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"เกิดข้อผิดพลาดระหว่างส่งออก: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"ชื่อไฟล์ที่ต้องระบุยาวเกินไป (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"ข้อผิดพลาด I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"หน่วยความจำไม่เพียงพอ ไฟล์อาจใหญ่เกินไป"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"ไม่สามารถแยกวิเคราะห์ vCard ด้วยเหตุผลที่ไม่คาดคิด"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"ไม่สนับสนุนรูปแบบนี้"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"ไม่สามารถรวบรวมข้อมูลเมตาของ vCard ที่ระบุ"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"ไม่สามารถนำเข้าไฟล์ตั้งแต่หนึ่งไฟล์ขึ้นไป (%s)"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"ส่งออก <xliff:g id="FILENAME">%s</xliff:g> เสร็จแล้ว"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"ยกเลิกการส่งออก <xliff:g id="FILENAME">%s</xliff:g> แล้ว"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"กำลังส่งออกข้อมูลสมุดโทรศัพท์"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"ไม่สามารถดึงข้อมูลจากฐานข้อมูล"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"ไม่มีรายชื่อติดต่อที่สามารถส่งออกได้ หากคุณมีรายชื่อติดต่ออยู่ในโทรศัพท์ของคุณจริงๆ อาจเป็นเพราะผู้ให้บริการข้อมูลบางรายไม่อนุญาตให้ส่งออกรายชื่อติดต่อจากโทรศัพท์"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"โปรแกรมเขียนข้อความ vCard เริ่มการทำงานไม่ถูกต้อง"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"ไม่สามารถส่งออก"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"ไม่ได้ส่งออกข้อมูลรายชื่อติดต่อ\nสาเหตุ: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"กำลังนำเข้า <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"ไม่สามารถอ่านข้อมูล vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"ยกเลิกการอ่านข้อมูล vCard แล้ว"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"นำเข้า vCard <xliff:g id="FILENAME">%s</xliff:g> เรียบร้อยแล้ว"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"ยกเลิกการนำเข้า <xliff:g id="FILENAME">%s</xliff:g> แล้ว"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"การนำเข้า <xliff:g id="FILENAME">%s</xliff:g> จะเกิดขึ้นในไม่ช้า"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"ไฟล์จะถููกนำเข้าในไม่ช้า"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"คำขอนำเข้า vCard ถูกปฏิเสธ ลองใหม่ภายหลัง"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"การส่งออก <xliff:g id="FILENAME">%s</xliff:g> จะเกิดขึ้นในไม่ช้า"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"คำขอส่งออก vCard ถูกปฏิเสธ ลองใหม่ภายหลัง"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"สมุดโทรศัพท์"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"กำลังแคช vCard ไปยังที่จัดเก็บข้อมูลชั่วคราวในตัวเครื่อง การนำเข้าจริงจะเริ่มต้นในอีกสักครู่"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"ไม่สามารถนำเข้า vCard"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"ผู้ติดต่อทาง NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"ส่งออกรายชื่อติดต่อ"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"กำลังแคช"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"กำลังนำเข้า <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"การตั้งค่า"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"แชร์สมุดโทรศัพท์ที่มองเห็น"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"นำเข้า/ส่งออกผู้ติดต่อ"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"นำเข้าสมุดโทรศัพท์"</string>
+ <string name="share_error" msgid="948429331673358107">"ไม่สามารถแชร์รายชื่อติดต่อนี้ได้"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"ค้นหา"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"รายชื่อติดต่อที่จะแสดง"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"รายชื่อติดต่อที่จะแสดง"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"รายการโปรด"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"ไม่มีรายชื่อติดต่อ"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"ล้างผู้ที่คุณติดต่อด้วยบ่อยๆ"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"เลือกซิมการ์ด"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"นำเข้า/ส่งออก"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"หมายเลขที่ถูกบล็อก"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"ผ่านทาง <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> ผ่านทาง <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"ล้างการค้นหา"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 5217780..9839b78 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Itakda ang default"</string>
<string name="clear_default" msgid="7193185801596678067">"I-clear ang default"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Kinopya ang teksto"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Gusto mo bang i-discard ang iyong mga pagbabago at huminto sa pag-e-edit?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"I-discard ang mga pagbabago?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"I-discard"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Patuloy na mag-edit"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Kanselahin"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Maghanap ng mga contact"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Alisin ang mga contact"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Tungkol dito"</string>
<string name="send_message" msgid="8938418965550543196">"Magpadala ng mensahe"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Lumilikha ng personal na kopya…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Kahapon"</string>
<string name="tomorrow" msgid="6241969467795308581">"Bukas"</string>
<string name="today" msgid="8041090779381781781">"Ngayon"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Ngayong <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Mga Mensahe"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Ayusin ang iyong listahan"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Linisin ang mga duplicate at igrupo ang mga contact ayon sa label"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Kinopya ang teksto"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopyahin sa clipboard"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Tawagan si <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Tawagan ang tahanan"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Tawagan ang mobile"</string>
+ <string name="call_work" msgid="5328785911463744028">"Tawagan ang trabaho"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Tawagan ang fax sa trabaho"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Tawagan ang fax sa tahanan"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Tawagan ang pager"</string>
+ <string name="call_other" msgid="8563753966926932052">"Tawag"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Tawagan ang pabalik na tawag"</string>
+ <string name="call_car" msgid="3280537320306436445">"Tawagan sa kotse"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Tawagan ang pangunahing kumpanya"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Tawagan ang ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Tawagan ang pangunahin"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Tawagan ang fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Tumawag sa radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Tawagan ang telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Tawagan ang TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Tawagan ang mobile sa trabaho"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Tawagan ang pager sa trabaho"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Tawagan si <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Tawagan ang MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Mag-text sa <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Mag-text sa bahay"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Mag-text sa mobile"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Mag-text sa trabaho"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Mag-text sa fax sa trabaho"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"I-text ang fax sa tahanan"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Mag-text sa pager"</string>
+ <string name="sms_other" msgid="806127844607642331">"Teksto"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"I-text ang callback"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Mag-text sa kotse"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Mag-text sa pangunahin ng kumpanya"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Mag-text sa ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"I-text ang pangunahin"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"I-text ang fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Mag-text sa radyo"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Mag-text sa telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"I-text ang TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"I-text ang mobile sa trabaho"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Mag-text sa pager sa trabaho"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Mag-text sa <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Mag-text ng MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"I-clear ang mga madalas tinatawagan?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Kini-clear ang mga madalas tinatawagan…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Available"</string>
+ <string name="status_away" msgid="1838861100379804730">"Malayo"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Busy"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Mga Contact"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Iba pa"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Direktoryo"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Lahat ng contact"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Naghahanap…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Higit sa <xliff:g id="COUNT">%d</xliff:g> ang natagpuan."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Walang mga contact"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ang nahanap</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ang nahanap</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Mabilisang contact para kay <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Walang pangalan)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Madalas na kino-contact"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Tingnan ang contact"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Lahat ng contact na may mga numero ng telepono"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Tingnan ang mga update"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Pangalan"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Palayaw"</string>
+ <string name="full_name" msgid="6602579550613988977">"Pangalan"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Prefix ng pangalan"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Gitnang pangalan"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Suffix ng pangalan"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Phonetic na pangalan"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Phonetic na gitnang pangalan"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telepono"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Email"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Address"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Samahan"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Kaugnayan"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Text message"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Address"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Kumpanya"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Pamagat"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Mga Tala"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Website"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Mag-email sa bahay"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Mag-email sa mobile"</string>
+ <string name="email_work" msgid="2807430017302722689">"Mag-email sa trabaho"</string>
+ <string name="email_other" msgid="3454004077967657109">"Email"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Email <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Email"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Kalye"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO box"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Kapitbahayan"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Lungsod"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Katayuan"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"ZIP code"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Bansa"</string>
+ <string name="map_home" msgid="1243547733423343982">"Tingnan ang home address"</string>
+ <string name="map_work" msgid="1360474076921878088">"Tingnan ang address ng trabaho"</string>
+ <string name="map_other" msgid="3817820803587012641">"Tingnan ang address"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Tingnan ang <xliff:g id="CUSTOM">%s</xliff:g> na address"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Makipag-chat gamit ang AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Makipag-chat gamit ang Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Makipag-chat gamit ang Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Makipag-chat gamit ang Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Makipag-chat gamit ang QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Makipag-chat gamit ang Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Makipag-chat gamit ang ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Makipag-chat gamit ang Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Makipag-chat"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"tanggalin"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Palawakin o tiklupin ang mga field ng pangalan"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Lahat ng mga contact"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Naka-star"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"I-customize"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Contact"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Lahat ng iba pang contact"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Lahat ng contact"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Alisin ang pangkat sa pag-sync"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Magdagdag ng pangkat sa pag-sync"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Higit pang mga pangkat…"</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Aalisin rin ng pag-aalis sa \"<xliff:g id="GROUP">%s</xliff:g>\" mula sa sync ang anumang mga hindi nakapangkat na contact mula sa sync."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Sine-save ang mga pagpipilian sa pagpapakita…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Tapos na"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Kanselahin"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"I-import mula sa SIM card"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Kanselahin ang pag-import ng <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Kanselahin ang pag-export ng <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Di makansela pag-import/pag-export vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Hindi kilalang error."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Hindi mabuksan ang \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Hindi masimulan ang exporter: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Walang maaaring i-export na contact."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Naganap ang isang error habang nag-e-export: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Masyadong mahaba ang kinakailangang filename (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O na error"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Walang sapat na memory. Maaaring masyadong malaki ang file."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Hindi ma-parse ang vCard dahil sa isang hindi inaasahang dahilan."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Hindi sinusuportahan ang format."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Hindi makakolekta ng impormasyon ng meta ng nasabing (mga) file ng vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Ang isa o higit pang mga file ay hindi ma-import (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Tapos na ang pag-export ng <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Kinansela ang pag-export ng <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Pag-e-export ng data ng contact"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Hindi makuha ang impormasyon ng database."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Walang mga maaaring i-export na contact. Kung mayroon kang mga contact sa iyong telepono, maaaring hindi pinapayagan ng ilang provider ng data na i-export mula sa telepono ang mga contact."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Hindi nagsimula nang tama ang composer ng vCard."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Hindi ma-export"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Hindi na-export ang data ng contact.\nDahilan: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Nag-iimport <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Hindi mabasa ang data ng vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Kinansela ang pagbabasa ng data ng vCard"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Tapos na ang pag-import ng vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Kinansela ang pag-import ng <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Mai-import ang <xliff:g id="FILENAME">%s</xliff:g> sa ilang saglit."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Sa ilang sandali ay mai-import na ang file."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Tinanggihan ang kahilingan sa pag-import ng vCard. Pakisubukang muli sa ibang pagkakataon."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Mae-export ang <xliff:g id="FILENAME">%s</xliff:g> sa ilang saglit."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Tinanggihan ang kahilingan sa pag-export ng vCard. Subukang muli sa ibang pagkakataon."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"contact"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Kina-cache ang (mga) vCard sa lokal na pansamantalang storage. Magsisimula sa lalong madaling panahon ang aktuwal na pag-import."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Hindi ma-import ang vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Natanggap ang contact sa NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"I-export ang mga contact?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Nagka-cache"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Nag-i-import <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Mga Setting"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Magbahagi ng mga nakikitang contact"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Mag-import/mag-export ng mga contact"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Mag-import ng mga contact"</string>
+ <string name="share_error" msgid="948429331673358107">"Hindi maibabahagi ang contact na ito."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Paghahanap"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Mga contact na ipapakita"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Mga contact na ipapakita"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Mga Paborito"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Walang mga contact."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"I-clear ang mga madadalas"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Pumili ng SIM card"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Mag-import/mag-export"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Mga naka-block na numero"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"sa pamamagitan ng <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> sa pamamagitan ng <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"I-clear ang paghahanap"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index eb98147..0087805 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Varsayılan olarak ayarla"</string>
<string name="clear_default" msgid="7193185801596678067">"Varsayılanları temizle"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Metin kopyalandı"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Değişiklikleriniz yok sayılsın ve düzenlemeden çıkılsın mı?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Değişiklikler iptal edilsin mi?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Yok say"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Düzenlemeye devam et"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"İptal"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Kişilerde arayın"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Kişileri kaldır"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Hakkında"</string>
<string name="send_message" msgid="8938418965550543196">"İleti gönder"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Kişisel kopya oluşturuluyor..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Dün"</string>
<string name="tomorrow" msgid="6241969467795308581">"Yarın"</string>
<string name="today" msgid="8041090779381781781">"Bugün"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Bugün şu saatler arasında: <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"İletiler"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Listenizi organize edin"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Yinelenen kişileri temizleyin ve kişileri etikete göre gruplandırın"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Metin kopyalandı"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Panoya kopyala"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Ara (<xliff:g id="CUSTOM">%s</xliff:g>)"</string>
+ <string name="call_home" msgid="1990519474420545392">"Çağrı yap (ev)"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Çağrı yap (mobil)"</string>
+ <string name="call_work" msgid="5328785911463744028">"Çağrı yap (iş)"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Çağrı yap (iş faksı)"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Çağrı yap (ev faksı)"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Çağrı yap (çağrı cihazı)"</string>
+ <string name="call_other" msgid="8563753966926932052">"Sesli arama yap"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Çağrı yap (geri arama)"</string>
+ <string name="call_car" msgid="3280537320306436445">"Çağrı yap (araç)"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Çağrı yap (şirket ana hattı)"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Çağrı yap (ISDN)"</string>
+ <string name="call_main" msgid="6082900571803441339">"Çağrı yap (ana hat)"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Faksı çağrı yap"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Çağrı yap (telsiz)"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Çağrı yap (teleks)"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Çağrı yap (TTY/TDD)"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Çağrı yap (iş cep telefonu)"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Çağrı yap (iş ç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">"Çağrı yap (MMS)"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"SMS Gönder ()"</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="3888842199855843152">"Faksa SMS gönder"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Sık iletişim kurulanlar silinsin mi?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Sık iletişim kurulanlar siliniyor…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Uygun"</string>
+ <string name="status_away" msgid="1838861100379804730">"Dışarıda"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Meşgul"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Kişiler"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Diğer"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Dizin"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Tüm kişiler"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Aranıyor…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g> kişiden fazla bulundu."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Hiç kişi yok"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> kişi bulundu</item>
+ <item quantity="one">1 kişi bulundu</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> için hızlı kişi"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Adsız)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Sık iletişim kurulanlar"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Kişiyi görüntüle"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Telefon numarası olan tüm kişiler"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Gncellmlri görüntüle"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Ad"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Takma ad"</string>
+ <string name="full_name" msgid="6602579550613988977">"Ad"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Fonetik ad"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Fonetik ikinci ad"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Telefon"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"E-posta"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Adres"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Kuruluş"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"İlişki"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Kısa mesaj"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Adres"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Şirket"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Başlık"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Notlar"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Web sitesi"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"E-posta"</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="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="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="3817820803587012641">"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="description_minus_button" msgid="6908099247930477551">"sil"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Ad alanlarını genişlet veya daralt"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Tüm kişiler"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Yıldızlı"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Özelleştir"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Kişi"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Diğer tüm kişiler"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Tüm kişiler"</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_warn_remove_ungrouped" msgid="8872290721676651414">"\"<xliff:g id="GROUP">%s</xliff:g>\" adlı grubu senkronizasyondan kaldırmak, gruplanmamış tüm kişilerin de senkronizasyondan kaldırılmasına neden olur."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Görüntüleme seçenekleri kaydediliyor..."</string>
+ <string name="menu_done" msgid="796017761764190697">"Bitti"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"İptal"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM karttan içe aktar"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> dosyasının içe aktarılması iptal edilsin mi?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> dosyasının dışa aktarılması iptal edilsin mi?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"İçe/dışa aktrma işlmi iptl edilemedi"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Bilinmeyen hata."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" açılamadı: <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Dışa aktarıcı başlatılamadı: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Dışa verilebilecek kişi yok."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Dışa aktarma sırasında bir hata oluştu: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Gereken dosya adı çok uzun (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"G/Ç Hatası"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Bellek yetersiz. Dosya çok büyük olabilir."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Beklenmeyen bir nedenden dolayı vCard ayrıştırılamadı."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Biçim desteklenmiyor."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Belirtilen vCard dosyalarının meta bilgileri toplanamadı."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Bir veya daha fazla dosya içe aktarılamadı (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> dosyasını dışa aktarma tamamlandı."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> dosyasını dışa aktarma iptal edildi."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Kişi verileri dışa aktarılıyor"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Veritabanı bilgileri alınamadı."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Dışa aktarabilir kişi yok. Telefonunuzda kişileriniz varsa, bazı veri sağlayıcıları kişilerin telefondan dışa aktarılmasına izin vermeyebilir."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard oluşturucu düzgün başlamadı."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Dışa aktarılamadı"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Kişi verileri dışa aktarılamadı.\nNedeni: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> içe aktarılıyor"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard verileri okunamadı"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard verilerini okuma işlemi iptal edildi"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g> dosysn içe aktarma tamamlandı"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> dosyasını içe aktarma iptal edildi"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> kısa bir süre içinde içe aktarılacak."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Dosya kısa bir süre sonra içe aktarılacaktır."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard\'ı içe aktarma isteği reddedildi. Daha sonra tekrar deneyin."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> kısa bir süre içinde dışa aktarılacak."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard\'ı dışa aktarma isteği reddedildi. Daha sonra tekrar deneyin."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"kişi"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard\'lar geçici bir yerel depolama alanında önbelleğe alınıyor. Asıl içe aktarma işlemi kısa süre içinde başlayacak."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard içe aktarılamadı."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Kişi NFC ile alındı"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Kişileri dışa aktar?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Önbelleğe alınıyor"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"İçe aktarılıyor <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Ayarlar"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Görülebilir kişileri paylaş"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Kişileri içe/dışa aktar"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Kişileri içe aktar"</string>
+ <string name="share_error" msgid="948429331673358107">"Bu kişi paylaşılamıyor."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Ara"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Görüntülenecek kişiler"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Görüntülenecek kişiler"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Sık Kullanılanlar"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Kişi yok."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Sık iletişim kurulanları sil"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM kart seç"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"İçe/Dışa Aktar"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Engellenen numaralar"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"<xliff:g id="SOURCE">%1$s</xliff:g> aracılığıyla"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="SOURCE">%2$s</xliff:g> üzerinden şu saatte: <xliff:g id="DATE">%1$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Aramayı temizle"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index e5a0b14..526c68e 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -246,9 +246,9 @@
<string name="set_default" msgid="4417505153468300351">"Установити за умовчанням"</string>
<string name="clear_default" msgid="7193185801596678067">"Очистити налаштування за умовчанням"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Текст скопійовано"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Відхилити зміни та закінчити редагування?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Відхилити зміни?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Відхилити"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Продовжити редагування"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Скасувати"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Пошук контактів"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Вилучити контакти"</string>
@@ -273,7 +273,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Інформація"</string>
<string name="send_message" msgid="8938418965550543196">"Надіслати повідомлення"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Створення особистої копії..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Учора"</string>
<string name="tomorrow" msgid="6241969467795308581">"Завтра"</string>
<string name="today" msgid="8041090779381781781">"Сьогодні"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Сьогодні о <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -364,4 +363,336 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Повідомлення"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Упорядкуйте свій список контактів"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Видаліть копії та групуйте контакти за мітками"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Текст скопійовано"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Копіювати в буфер обміну"</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="8563753966926932052">"Набрати"</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="5745314124619636674">"Набрати факс"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"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="3888842199855843152">"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">"SMS на TTY/TDD"</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">"SMS на <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"SMS на ном. MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Очистити список частих контактів?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Очищення списку частих контактів…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Доступний"</string>
+ <string name="status_away" msgid="1838861100379804730">"Не на місці"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Зайнятий"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Контакти"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Інші"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Каталог"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Усі контакти"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Пошук..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Знайдено понад <xliff:g id="COUNT">%d</xliff:g>."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Контактів немає"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one">Знайдено <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="few">Знайдено <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="many">Знайдено <xliff:g id="COUNT">%d</xliff:g></item>
+ <item quantity="other">Знайдено <xliff:g id="COUNT">%d</xliff:g></item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Швидкий контакт із: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Без імені)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Часті контакти"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Переглянути контакт"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Усі контакти з номерами телефону"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Переглян. оновлення"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Ім\'я"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Псевдонім"</string>
+ <string name="full_name" msgid="6602579550613988977">"Ім\'я"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"Вимова імені"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Вимова по-батькові"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Телеф."</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Ел.адр."</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Адреса"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"Чат"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Організація"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Стосунки"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Текстове повідомлення"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Адреса"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Компанія"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Назва"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Примітки"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Веб-сайт"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"Надісл. ел.лист"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Написати на <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Відправ."</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="map_home" msgid="1243547733423343982">"Див. дом. адресу"</string>
+ <string name="map_work" msgid="1360474076921878088">"Див. роб. адресу"</string>
+ <string name="map_other" msgid="3817820803587012641">"Див. адресу"</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="description_minus_button" msgid="6908099247930477551">"видалити"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Розгорнути або згорнути поля імен"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Усі контакти"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Із зірочкою"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Налаштувати"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Контакт"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Усі інші контакти"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Усі контакти"</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_warn_remove_ungrouped" msgid="8872290721676651414">"Видалення групи \"<xliff:g id="GROUP">%s</xliff:g>\" із синхронізації призведе до припинення синхронізації незгрупованих контактів."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Зберіг-ня парам. відображ…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Готово"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Скасувати"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Імпорт із SIM-карти"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Скасувати імпорт файлу <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Скасувати експорт файлу <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Не вдалося скасув. імпорт/експорт vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Невідома помилка."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Не вдалося відкрити файл \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Не вдалося запустити експортер: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Немає контакту, який можна експортувати."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Під час експорту сталася помилка: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Потрібна назва файлу задовга (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Помилка вводу/виводу"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Недостатньо пам’яті. Можливо, файл завеликий."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Не вдалося проаналізувати vCard через неочікувану причину."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Формат не підтримується."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Не вдалося зібрати мета-інформацію файлів цієї vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Не вдалося імпортувати один або кілька файлів (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Експорт файлу <xliff:g id="FILENAME">%s</xliff:g> завершено."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Експорт файлу <xliff:g id="FILENAME">%s</xliff:g> скасовано."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Експорт. контактні дані"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Не вдалось отримати інформацію бази даних."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Немає контактів, які можна експортувати. Якщо у вашому телефоні є контакти, можливо, якийсь постачальник даних заборонив експорт контактів із телефону."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Майстер vCard не запущено належним чином."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Помилка експорту"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Контактні дані не експортовано.\nПричина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Імпорт <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Не вдалося прочитати дані vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Читання даних vCard скасовано"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Імпорт файлу <xliff:g id="FILENAME">%s</xliff:g> vCard завершено"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Імпорт файлу <xliff:g id="FILENAME">%s</xliff:g> скасовано"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"Файл <xliff:g id="FILENAME">%s</xliff:g> незабаром буде імпортовано."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Незабаром файл буде імпортовано."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Запит на імпорт файлу vCard відхилено. Повторіть спробу пізніше."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"Файл <xliff:g id="FILENAME">%s</xliff:g> незабаром буде експортовано."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Запит на експорт файлу vCard відхилено. Повторіть спробу пізніше."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"контакт"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Кешування файлів vCard у локальну тимчасову пам’ять. Імпорт почнеться незабаром."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Не вдалось імпортувати файл vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Конт., отрим.через NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Експортув. контакти?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Кешування"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Імпорт <xliff:g id="CURRENT_NUMBER">%s</xliff:g> з <xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Налаштування"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Передати видимі контакти"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Імпорт/експорт контактів"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Імпорт контактів"</string>
+ <string name="share_error" msgid="948429331673358107">"Цей контакт неможливо надіслати."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Пошук"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Контакти для показу"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Контакти для показу"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Вибране"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Контактів немає."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Очистити часті контакти"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Вибрати SIM-карту"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Імпорт або експорт"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Заблоковані номери"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"через <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> через <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Очистити поле пошуку"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
index adf405f..b8a3112 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur-rPK/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"ڈیفالٹ طے کریں"</string>
<string name="clear_default" msgid="7193185801596678067">"ڈیفالٹ کو صاف کریں"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"متن کاپی ہوگیا"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"اپنی تبدیلیاں مسترد کریں اور ترمیم کرنا چھوڑ دیں؟"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"تبدیلیاں مسترد کریں؟"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"رد کریں"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"ترمیم کرنا جاری رکھیں"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"منسوخ کریں"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"رابطے تلاش کریں"</string>
<string name="title_edit_group" msgid="8602752287270586734">"رابطے ہٹائیں"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"تفصیل"</string>
<string name="send_message" msgid="8938418965550543196">"پیغام بھیجیں"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"ایک ذاتی کاپی بنا رہا ہے…"</string>
- <string name="yesterday" msgid="6840858548955018569">"گزشتہ کل"</string>
<string name="tomorrow" msgid="6241969467795308581">"آئندہ کل"</string>
<string name="today" msgid="8041090779381781781">"ﺁﺝ"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"آج بوقت <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"پیغامات"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"اپنی فہرست کو منظم کریں"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"ڈپلیکیٹس صاف کریں اور رابطوں کو بلحاظ لیبل گروپ کریں"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"متن کاپی ہوگیا"</string>
+ <string name="copy_text" msgid="3257145021583508761">"کلپ بورڈ میں کاپی کریں"</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="8563753966926932052">"کال کریں"</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="5745314124619636674">"فیکس پر کال کریں"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"متن بھیجیں"</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="3888842199855843152">"فیکس نمبر پر متن بھیجیں"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"اکثر رابطہ کردہ کو صاف کریں؟"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"اکثر رابطہ کردہ کو صاف کر رہا ہے…"</string>
+ <string name="status_available" msgid="5586870015822828392">"دستیاب"</string>
+ <string name="status_away" msgid="1838861100379804730">"دور"</string>
+ <string name="status_busy" msgid="9147992455450257136">"مصروف"</string>
+ <string name="contactsList" msgid="8661624236494819731">"رابطے"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"دیگر"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"ڈائریکٹری"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"سبھی رابطے"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"تلاش کر رہا ہے…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"<xliff:g id="COUNT">%d</xliff:g> سے زیادہ ملے۔"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"کوئی رابطے نہیں ہیں"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ملے</item>
+ <item quantity="one">1 ملا</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g> کیلئے فوری رابطہ"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(کوئی نام نہیں)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"اکثر رابطہ کردہ"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"رابطہ دیکھیں"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"فون نمبرز والے سبھی رابطے"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"اپ ڈیٹس دیکھیں"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"نام"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"عرفی نام"</string>
+ <string name="full_name" msgid="6602579550613988977">"نام"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"فونیٹک نام"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"فونیٹک درمیانی نام"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"فون"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"ای میل"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"پتہ"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"تنظیم"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"تعلق"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"متنی پیغام"</string>
+ <string name="postal_address" msgid="8765560217149624536">"پتہ"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"کمپنی"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"عنوان"</string>
+ <string name="label_notes" msgid="8337354953278341042">"نوٹس"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"ویب سائٹ"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"ای میل"</string>
+ <string name="email_custom" msgid="7548003991586214105">"<xliff:g id="CUSTOM">%s</xliff:g> کو ای میل کریں"</string>
+ <string name="email" msgid="5668400997660065897">"ای میل"</string>
+ <string name="postal_street" msgid="8133143961580058972">"اسٹریٹ"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO باکس"</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="map_home" msgid="1243547733423343982">"گھر کا پتہ دیکھیں"</string>
+ <string name="map_work" msgid="1360474076921878088">"دفتر کا پتہ دیکھیں"</string>
+ <string name="map_other" msgid="3817820803587012641">"پتہ دیکھیں"</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="description_minus_button" msgid="6908099247930477551">"حذف کریں"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"نام کی فیلڈز کو پھیلائیں یا سکیڑیں"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"سبھی رابطے"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"ستارے کے نشان والے"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"مرضی کے مطابق بنائیں"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"رابطہ"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"سبھی دیگر رابطے"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"سبھی رابطے"</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_warn_remove_ungrouped" msgid="8872290721676651414">"\"<xliff:g id="GROUP">%s</xliff:g>\" کو مطابقت پذیری سے ہٹانے سے مطابقت پذیری سے گروپ سے خارج کردہ کوئی رابطے بھی ہٹ جائیں گے۔"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"ڈسپلے کے اختیارات محفوظ کر رہا ہے…"</string>
+ <string name="menu_done" msgid="796017761764190697">"ہوگیا"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"منسوخ کریں"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"SIM کارڈ سے درآمد کریں"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"<xliff:g id="FILENAME">%s</xliff:g> کی درآمد منسوخ کریں"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"<xliff:g id="FILENAME">%s</xliff:g> کی برآمد منسوخ کریں؟"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"vCard کی درآمد/برآمد کو منسوخ نہیں کرسکا"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"نامعلوم خرابی۔"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"\"<xliff:g id="FILE_NAME">%s</xliff:g>\" کو نہیں کھول سکا: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"۔"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"برآمد کنندہ شروع نہیں ہو سکا: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"۔"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"کوئی قابل برآمد رابطہ نہیں ہے۔"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"برآمد کرنے کے دوران ایک خرابی پیش آگئی: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"۔"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"مطلوبہ فائل کا نام کافی بڑا (\"<xliff:g id="FILENAME">%s</xliff:g>\") ہے۔"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O خرابی"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"کافی میموری نہیں ہے۔ فائل کافی بڑی ہو سکتی ہے۔"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"ایک غیر متوقع وجہ سے vCard کو پارس نہیں کرسکا۔"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"فارمیٹ تعاون یافتہ نہیں ہے۔"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"مقررہ vCard فائل (فائلوں) کی میٹا معلومات اکٹھا نہیں کرسکا۔"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"ایک یا مزید فائلیں درآمد نہیں ہوسکیں (%s)۔"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"<xliff:g id="FILENAME">%s</xliff:g> کی برآمد مکمل ہوگئی۔"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"<xliff:g id="FILENAME">%s</xliff:g> کی برآمد منسوخ ہوگئی۔"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"رابطہ کا ڈیٹا برآمد کر رہا ہے"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"ڈیٹابیس کی معلومات حاصل نہیں ہو سکی۔"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"برآمد کرنے لائق کوئی رابطے نہیں ہیں۔ اگر آپ کے فون پر واقعی رابطے ہیں تو ممکن ہے کچھ ڈیٹا فراہم کنندگان رابطوں کو فون سے برآمد کیے جانے کی اجازت نہ دیتے ہوں۔"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard کمپوزر مناسب طریقے سے شروع نہیں ہوا۔"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"برآمد نہیں کیا جاسکا"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"رابطوں کا ڈیٹا برآمد نہیں ہوا۔\nوجہ: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"<xliff:g id="NAME">%s</xliff:g> کو درآمد کر رہا ہے"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"vCard کا ڈیٹا نہیں پڑھ سکا"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"vCard کا ڈیٹا پڑھنا منسوخ ہوگیا"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"vCard <xliff:g id="FILENAME">%s</xliff:g> کی درآمد پوری ہوگئی"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"<xliff:g id="FILENAME">%s</xliff:g> کی درآمد منسوخ ہوگئی"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> جلد ہی درآمد کی جائے گی۔"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"فائل جلد ہی درآمد کی جائے گی۔"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard درآمد کرنے کی درخواست مسترد ہوگئی تھی۔ بعد میں دوبارہ کوشش کریں۔"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> جلد ہی برآمد کی جائے گی۔"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard برآمد کرنے کی درخواست مسترد ہوگئی تھی۔ بعد میں دوبارہ کوشش کریں۔"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"رابطہ"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"vCard(s) کو مقامی عارضی اسٹوریج میں ذخیرہ کر رہا ہے۔ اصل درآمد جلد ہی شروع ہوگی۔"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"vCard درآمد نہیں کرسکا۔"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"NFC پر موصولہ رابطہ"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"رابطے برآمد کریں؟"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"ذخیرہ کر رہا ہے"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"<xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g> درآمد کر رہا ہے"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"ترتیبات"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"مرئی رابطوں کا اشتراک کریں"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"رابطے درآمد/برآمد کریں"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"رابطے درآمد کریں"</string>
+ <string name="share_error" msgid="948429331673358107">"اس رابطہ کا اشتراک نہیں کیا جا سکتا۔"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"تلاش کریں"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"ڈسپلے کرنے کیلئے رابطے"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"ڈسپلے کرنے کیلئے رابطے"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"پسندیدہ"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"کوئی رابطے نہیں ہیں۔"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"اکثر و بیشتر کو صاف کریں"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM کارڈ منتخب کریں"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"درآمد/برآمد کریں"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"مسدود کردہ نمبرز"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"بذریعہ <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> بذریعہ <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"تلاش صاف کریں"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index d140126..d81f404 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Standart sifatida o‘rnatish"</string>
<string name="clear_default" msgid="7193185801596678067">"Standartni tozalash"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Matndan nuxsa olindi"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"O‘zgarishlar bekor qilinib, chiqib ketilsinmi?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"O‘zgarishlar bekor qilinsinmi?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Bekor qilish"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Tahrirlashda davom etish"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Bekor qilish"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Kontaktlarni qidirish"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Kontaktlarni olib tashlash"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Ma’lumot"</string>
<string name="send_message" msgid="8938418965550543196">"Xabar yuborish"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Shaxsiy nusxasi yaratilmoqda…"</string>
- <string name="yesterday" msgid="6840858548955018569">"Kecha"</string>
<string name="tomorrow" msgid="6241969467795308581">"Ertaga"</string>
<string name="today" msgid="8041090779381781781">"Bugun"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Bugun <xliff:g id="TIME_INTERVAL">%s</xliff:g> da"</string>
@@ -342,4 +341,505 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Xabarlar"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Kontaktlarni tartibga soling"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Kontaktlarni yorliq bo‘yicha guruhlang va takroriy kontaktlarni o‘chirib tashlang"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Matndan nuxsa olindi"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Vaqtinchalik xotiraga nusxalash"</string>
+ <!-- no translation found for call_custom (7756571794763171802) -->
+ <skip />
+ <!-- no translation found for call_home (1990519474420545392) -->
+ <skip />
+ <!-- no translation found for call_mobile (7502236805487609178) -->
+ <skip />
+ <!-- no translation found for call_work (5328785911463744028) -->
+ <skip />
+ <!-- no translation found for call_fax_work (7467763592359059243) -->
+ <skip />
+ <!-- no translation found for call_fax_home (8342175628887571876) -->
+ <skip />
+ <!-- no translation found for call_pager (9003902812293983281) -->
+ <skip />
+ <!-- no translation found for call_other (8563753966926932052) -->
+ <skip />
+ <!-- no translation found for call_callback (1910165691349426858) -->
+ <skip />
+ <!-- no translation found for call_car (3280537320306436445) -->
+ <skip />
+ <!-- no translation found for call_company_main (6105120947138711257) -->
+ <skip />
+ <!-- no translation found for call_isdn (1541590690193403411) -->
+ <skip />
+ <!-- no translation found for call_main (6082900571803441339) -->
+ <skip />
+ <!-- no translation found for call_other_fax (5745314124619636674) -->
+ <skip />
+ <!-- no translation found for call_radio (8296755876398357063) -->
+ <skip />
+ <!-- no translation found for call_telex (2223170774548648114) -->
+ <skip />
+ <!-- no translation found for call_tty_tdd (8951266948204379604) -->
+ <skip />
+ <!-- no translation found for call_work_mobile (8707874281430105394) -->
+ <skip />
+ <!-- no translation found for call_work_pager (3419348514157949008) -->
+ <skip />
+ <!-- no translation found for call_assistant (2141641383068514308) -->
+ <skip />
+ <!-- no translation found for call_mms (6274041545876221437) -->
+ <skip />
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <!-- no translation found for sms_custom (5932736853732191825) -->
+ <skip />
+ <!-- no translation found for sms_home (7524332261493162995) -->
+ <skip />
+ <!-- no translation found for sms_mobile (5200107250451030769) -->
+ <skip />
+ <!-- no translation found for sms_work (2269624156655267740) -->
+ <skip />
+ <!-- no translation found for sms_fax_work (8028189067816907075) -->
+ <skip />
+ <!-- no translation found for sms_fax_home (9204042076306809634) -->
+ <skip />
+ <!-- no translation found for sms_pager (7730404569637015192) -->
+ <skip />
+ <!-- no translation found for sms_other (806127844607642331) -->
+ <skip />
+ <!-- no translation found for sms_callback (5004824430094288752) -->
+ <skip />
+ <!-- no translation found for sms_car (7444227058437359641) -->
+ <skip />
+ <!-- no translation found for sms_company_main (118970873419678087) -->
+ <skip />
+ <!-- no translation found for sms_isdn (8153785037515047845) -->
+ <skip />
+ <!-- no translation found for sms_main (8621625784504541679) -->
+ <skip />
+ <!-- no translation found for sms_other_fax (3888842199855843152) -->
+ <skip />
+ <!-- no translation found for sms_radio (3329166673433967820) -->
+ <skip />
+ <!-- no translation found for sms_telex (9034802430065267848) -->
+ <skip />
+ <!-- no translation found for sms_tty_tdd (6782284969132531532) -->
+ <skip />
+ <!-- no translation found for sms_work_mobile (2459939960512702560) -->
+ <skip />
+ <!-- no translation found for sms_work_pager (5566924423316960597) -->
+ <skip />
+ <!-- no translation found for sms_assistant (2773424339923116234) -->
+ <skip />
+ <!-- no translation found for sms_mms (4069352461380762677) -->
+ <skip />
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation_title (766292372438450432) -->
+ <skip />
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <!-- no translation found for clearFrequentsProgress_title (5157001637482794212) -->
+ <skip />
+ <!-- no translation found for status_available (5586870015822828392) -->
+ <skip />
+ <!-- no translation found for status_away (1838861100379804730) -->
+ <skip />
+ <!-- no translation found for status_busy (9147992455450257136) -->
+ <skip />
+ <string name="contactsList" msgid="8661624236494819731">"Kontaktlar"</string>
+ <!-- no translation found for local_invisible_directory (6046691709127661065) -->
+ <skip />
+ <!-- no translation found for directory_search_label (1887759056597975053) -->
+ <skip />
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <!-- no translation found for local_search_label (2551177578246113614) -->
+ <skip />
+ <string name="search_results_searching" msgid="3984833028938569930">"Qidirilmoqda…"</string>
+ <!-- no translation found for foundTooManyContacts (5163335650920020220) -->
+ <skip />
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Hech qanday kontakt yo‘q."</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ta topildi</item>
+ <item quantity="one">1 ta topildi</item>
+ </plurals>
+ <!-- no translation found for description_quick_contact_for (6737516415168327789) -->
+ <skip />
+ <!-- no translation found for missing_name (8745511583852904385) -->
+ <skip />
+ <!-- no translation found for favoritesFrequentContacted (6184232487472425690) -->
+ <skip />
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Kontaktni ko‘rish"</string>
+ <!-- no translation found for list_filter_phones (735313795643493365) -->
+ <skip />
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <!-- no translation found for view_updates_from_group (1782685984905600034) -->
+ <skip />
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <!-- no translation found for nameLabelsGroup (2034640839640477827) -->
+ <skip />
+ <!-- no translation found for nicknameLabelsGroup (2891682101053358010) -->
+ <skip />
+ <!-- no translation found for full_name (6602579550613988977) -->
+ <skip />
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <!-- no translation found for name_prefix (59756378548779822) -->
+ <skip />
+ <!-- no translation found for name_middle (8467433655992690326) -->
+ <skip />
+ <!-- no translation found for name_suffix (3855278445375651441) -->
+ <skip />
+ <!-- no translation found for name_phonetic (4259595234312430484) -->
+ <skip />
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <!-- no translation found for name_phonetic_middle (8643721493320405200) -->
+ <skip />
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <!-- no translation found for phoneLabelsGroup (6468091477851199285) -->
+ <skip />
+ <!-- no translation found for emailLabelsGroup (8389931313045344406) -->
+ <skip />
+ <!-- no translation found for postalLabelsGroup (3487738141112589324) -->
+ <skip />
+ <!-- no translation found for imLabelsGroup (3898238486262614027) -->
+ <skip />
+ <!-- no translation found for organizationLabelsGroup (2478611760751832035) -->
+ <skip />
+ <!-- no translation found for relationLabelsGroup (1854373894284572781) -->
+ <skip />
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <!-- no translation found for sms (1756857139634224222) -->
+ <skip />
+ <!-- no translation found for postal_address (8765560217149624536) -->
+ <skip />
+ <!-- no translation found for ghostData_company (5414421120553765775) -->
+ <skip />
+ <!-- no translation found for ghostData_title (7496735200318496110) -->
+ <skip />
+ <!-- no translation found for label_notes (8337354953278341042) -->
+ <skip />
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <!-- no translation found for websiteLabelsGroup (4202998982804009261) -->
+ <skip />
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <!-- no translation found for email_home (8573740658148184279) -->
+ <skip />
+ <!-- no translation found for email_mobile (2042889209787989814) -->
+ <skip />
+ <!-- no translation found for email_work (2807430017302722689) -->
+ <skip />
+ <!-- no translation found for email_other (3454004077967657109) -->
+ <skip />
+ <!-- no translation found for email_custom (7548003991586214105) -->
+ <skip />
+ <!-- no translation found for email (5668400997660065897) -->
+ <skip />
+ <!-- no translation found for postal_street (8133143961580058972) -->
+ <skip />
+ <!-- no translation found for postal_pobox (4431938829180269821) -->
+ <skip />
+ <!-- no translation found for postal_neighborhood (1450783874558956739) -->
+ <skip />
+ <!-- no translation found for postal_city (6597491300084895548) -->
+ <skip />
+ <!-- no translation found for postal_region (6045263193478437672) -->
+ <skip />
+ <!-- no translation found for postal_postcode (572136414136673751) -->
+ <skip />
+ <!-- no translation found for postal_country (7638264508416368690) -->
+ <skip />
+ <!-- no translation found for map_home (1243547733423343982) -->
+ <skip />
+ <!-- no translation found for map_work (1360474076921878088) -->
+ <skip />
+ <!-- no translation found for map_other (3817820803587012641) -->
+ <skip />
+ <!-- no translation found for map_custom (6184363799976265281) -->
+ <skip />
+ <!-- no translation found for chat_aim (2588492205291249142) -->
+ <skip />
+ <!-- no translation found for chat_msn (8041633440091073484) -->
+ <skip />
+ <!-- no translation found for chat_yahoo (6629211142719943666) -->
+ <skip />
+ <!-- no translation found for chat_skype (1210045020427480566) -->
+ <skip />
+ <!-- no translation found for chat_qq (4294637812847719693) -->
+ <skip />
+ <!-- no translation found for chat_gtalk (981575737258117697) -->
+ <skip />
+ <!-- no translation found for chat_icq (8438405386153745775) -->
+ <skip />
+ <!-- no translation found for chat_jabber (7561444230307829609) -->
+ <skip />
+ <!-- no translation found for chat (9025361898797412245) -->
+ <skip />
+ <!-- no translation found for description_minus_button (6908099247930477551) -->
+ <skip />
+ <!-- no translation found for expand_collapse_name_fields_description (8682630859539604311) -->
+ <skip />
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <!-- no translation found for list_filter_all_accounts (8908683398914322369) -->
+ <skip />
+ <!-- no translation found for list_filter_all_starred (5031734941601931356) -->
+ <skip />
+ <!-- no translation found for list_filter_customize (4789963356004169321) -->
+ <skip />
+ <!-- no translation found for list_filter_single (5871400283515893087) -->
+ <skip />
+ <!-- no translation found for display_ungrouped (6885954210243119591) -->
+ <skip />
+ <!-- no translation found for display_all_contacts (2031647544742889505) -->
+ <skip />
+ <!-- no translation found for menu_sync_remove (3266725887008450161) -->
+ <skip />
+ <!-- no translation found for dialog_sync_add (8267045393119375803) -->
+ <skip />
+ <!-- no translation found for display_more_groups (2682547080423434170) -->
+ <skip />
+ <!-- no translation found for display_warn_remove_ungrouped (8872290721676651414) -->
+ <skip />
+ <!-- no translation found for savingDisplayGroups (2133152192716475939) -->
+ <skip />
+ <!-- no translation found for menu_done (796017761764190697) -->
+ <skip />
+ <!-- no translation found for menu_doNotSave (58593876893538465) -->
+ <skip />
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <!-- no translation found for import_from_sim (3859272228033941659) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <!-- no translation found for cancel_import_confirmation_message (3929951040347726757) -->
+ <skip />
+ <!-- no translation found for cancel_export_confirmation_message (1995462401949262638) -->
+ <skip />
+ <!-- no translation found for cancel_vcard_import_or_export_failed (6139900383366166706) -->
+ <skip />
+ <!-- no translation found for fail_reason_unknown (1714092345030570863) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_open_file (2067725459821997463) -->
+ <skip />
+ <!-- no translation found for fail_reason_could_not_initialize_exporter (707260459259688510) -->
+ <skip />
+ <!-- no translation found for fail_reason_no_exportable_contact (8728506011371262065) -->
+ <skip />
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <!-- no translation found for fail_reason_error_occurred_during_export (3018855323913649063) -->
+ <skip />
+ <!-- no translation found for fail_reason_too_long_filename (3393764245254738333) -->
+ <skip />
+ <!-- no translation found for fail_reason_io_error (6748358842976073255) -->
+ <skip />
+ <!-- no translation found for fail_reason_low_memory_during_import (875222757734882898) -->
+ <skip />
+ <!-- no translation found for fail_reason_vcard_parse_error (888263542360355784) -->
+ <skip />
+ <!-- no translation found for fail_reason_not_supported (8219562769267148825) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_collect_vcard_meta_info (6427931733267328564) -->
+ <skip />
+ <!-- no translation found for fail_reason_failed_to_read_files (5823434810622484922) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title (4767045779458185251) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_canceled_title (2652222370493306887) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_title (9072240631534457415) -->
+ <skip />
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <!-- no translation found for composer_failed_to_get_database_infomation (1765944280846236723) -->
+ <skip />
+ <!-- no translation found for composer_has_no_exportable_contact (3296493229040294335) -->
+ <skip />
+ <!-- no translation found for composer_not_initialized (2321648986367005254) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_title (4892358112409576342) -->
+ <skip />
+ <!-- no translation found for exporting_contact_failed_message (4938527850142003141) -->
+ <skip />
+ <!-- no translation found for importing_vcard_description (4245275224298571351) -->
+ <skip />
+ <!-- no translation found for reading_vcard_failed_title (4251647443358422855) -->
+ <skip />
+ <!-- no translation found for reading_vcard_canceled_title (1925216585981542019) -->
+ <skip />
+ <!-- no translation found for importing_vcard_finished_title (3341541727268747967) -->
+ <skip />
+ <!-- no translation found for importing_vcard_canceled_title (2147475978165599336) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message (2804911199145873396) -->
+ <skip />
+ <!-- no translation found for vcard_import_will_start_message_with_default_name (1022969530654129470) -->
+ <skip />
+ <!-- no translation found for vcard_import_request_rejected_message (2890471184508516011) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message (2210241345252081463) -->
+ <skip />
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <!-- no translation found for vcard_export_request_rejected_message (2844874826431327531) -->
+ <skip />
+ <!-- no translation found for vcard_unknown_filename (7171709890959915954) -->
+ <skip />
+ <!-- no translation found for caching_vcard_message (4926308675041506756) -->
+ <skip />
+ <!-- no translation found for vcard_import_failed (5223531255894842406) -->
+ <skip />
+ <!-- no translation found for nfc_vcard_file_name (2823095213265993609) -->
+ <skip />
+ <!-- no translation found for confirm_export_title (6834385377255286349) -->
+ <skip />
+ <!-- no translation found for caching_vcard_title (1226272312940516605) -->
+ <skip />
+ <!-- no translation found for progress_notifier_message (2311011466908220528) -->
+ <skip />
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Sozlamalar"</string>
+ <!-- no translation found for share_visible_contacts (890150378880783797) -->
+ <skip />
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <!-- no translation found for dialog_import_export (4360648034889921624) -->
+ <skip />
+ <!-- no translation found for dialog_import (2431698729761448759) -->
+ <skip />
+ <!-- no translation found for share_error (948429331673358107) -->
+ <skip />
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <!-- no translation found for menu_search (9147752853603483719) -->
+ <skip />
+ <!-- no translation found for menu_contacts_filter (2165153460860262501) -->
+ <skip />
+ <!-- no translation found for activity_title_contacts_filter (8275542497615516969) -->
+ <skip />
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <!-- no translation found for contactsFavoritesLabel (8417039765586853670) -->
+ <skip />
+ <!-- no translation found for listTotalAllContactsZero (5513001821794568211) -->
+ <skip />
+ <!-- no translation found for menu_clear_frequents (7688250191932838833) -->
+ <skip />
+ <string name="menu_select_sim" msgid="3603578201960504010">"SIM kartani tanlash"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <!-- no translation found for menu_import_export (26217871113229507) -->
+ <skip />
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Bloklangan raqamlar"</string>
+ <!-- no translation found for contact_status_update_attribution (752179367353018597) -->
+ <skip />
+ <!-- no translation found for contact_status_update_attribution_with_date (7358045508107825068) -->
+ <skip />
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Izlashni tozalash"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 5ffec07..1ef7654 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Đặt mặc định"</string>
<string name="clear_default" msgid="7193185801596678067">"Xóa mặc định"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Đã sao chép văn bản"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Hủy các thay đổi của bạn và thoát chỉnh sửa?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Hủy thay đổi?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Hủy"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Tiếp tục chỉnh sửa"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Hủy"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Tìm kiếm trong danh bạ"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Xóa liên hệ"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Giới thiệu"</string>
<string name="send_message" msgid="8938418965550543196">"Gửi tin nhắn"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Đang tạo bản sao cá nhân..."</string>
- <string name="yesterday" msgid="6840858548955018569">"Hôm qua"</string>
<string name="tomorrow" msgid="6241969467795308581">"Ngày mai"</string>
<string name="today" msgid="8041090779381781781">"Hôm nay"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Hôm nay lúc <xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Tin nhắn"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Sắp xếp danh sách của bạn"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Xóa liên hệ trùng lặp và nhóm các liên hệ theo nhãn"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Đã sao chép văn bản"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Sao chép vào khay nhớ tạm"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Gọi <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Gọi số điện thoại nhà riêng"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Gọi số điện thoại di động"</string>
+ <string name="call_work" msgid="5328785911463744028">"Gọi số điện thoại cơ quan"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Gọi số fax cơ quan"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Gọi số fax nhà riêng"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Gọi số máy nhắn tin"</string>
+ <string name="call_other" msgid="8563753966926932052">"Gọi"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Gọi số gọi lại"</string>
+ <string name="call_car" msgid="3280537320306436445">"Gọi số điện thoại trên ô tô"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Gọi số điện thoại chính của công ty"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Gọi ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Gọi số điện thoại chính"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Gọi số fax"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Gọi số điện thoại radio"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Gọi số telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Gọi số điện thoại TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Gọi số điện thoại di động tại cơ quan"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Gọi số máy nhắn tin tại cơ quan"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Gọi <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Gọi MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">"Nhắn tin <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Nhắn tin tới số điện thoại nhà riêng"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Nhắn tin tới số điện thoại di động"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Nhắn tin tới số điện thoại cơ quan"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Nhắn tin tới số fax cơ quan"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Nhắn tin tới số fax nhà riêng"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Nhắn tin tới số máy nhắn tin"</string>
+ <string name="sms_other" msgid="806127844607642331">"Nhắn tin"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Nhắn tin tới số gọi lại"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Nhắn tin tới số điện thoại trên ô tô"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Nhắn tin tới số điện thoại chính của công ty"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Nhắn tin tới số điện thoại ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Nhắn tin tới số điện thoại chính"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Nhắn tin tới số fax"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Nhắn tin tới số điện thoại radio"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Nhắn tin tới số telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Nhắn tới số TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Nhắn tới số điện thoại di động tại cơ quan"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Nhắn tin tới số máy nhắn tin tại cơ quan"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Nhắn tin <xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Nhắn tin tới số điện thoại MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Xóa danh sách liên hệ thường xuyên?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Đang xóa DS liên hệ thường xuyên…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Có mặt"</string>
+ <string name="status_away" msgid="1838861100379804730">"Vắng mặt"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Bận"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Danh bạ"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Khác"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Thư mục"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Tất cả địa chỉ liên hệ"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Đang tìm kiếm…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"Đã tìm thấy hơn <xliff:g id="COUNT">%d</xliff:g> địa chỉ liên hệ."</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Không có địa chỉ liên hệ nào"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">Đã tìm thấy <xliff:g id="COUNT">%d</xliff:g> liên hệ</item>
+ <item quantity="one">Đã tìm thấy 1 liên hệ</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Liên hệ nhanh cho <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(Không có tên)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Thường xuyên được liên hệ"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Xem địa chỉ liên hệ"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Tất cả địa chỉ liên hệ có số điện thoại"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Xem thông tin c.nhật"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Tên"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Biệt hiệu"</string>
+ <string name="full_name" msgid="6602579550613988977">"Tên"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Tiền tố tên"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Tên đệm"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Hậu tố tên"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Tên theo phiên âm"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Tên đệm đúng phát âm"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Điện thoại"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"Email"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Địa chỉ"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Tổ chức"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Mối quan hệ"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Tin nhắn văn bản"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Địa chỉ"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Công ty"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Tiêu đề"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Ghi chú"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Trang web"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Gửi email tới địa chỉ email nhà riêng"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Gửi email tới địa chỉ email điện thoại di động"</string>
+ <string name="email_work" msgid="2807430017302722689">"Gửi email tới địa chỉ email cơ quan"</string>
+ <string name="email_other" msgid="3454004077967657109">"Gửi email"</string>
+ <string name="email_custom" msgid="7548003991586214105">"Gửi email cho <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"Gửi email"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Đường phố"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"Hộp thư bưu điện"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Vùng lân cận"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Thành phố"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Tiểu bang"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Mã ZIP"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Quốc gia"</string>
+ <string name="map_home" msgid="1243547733423343982">"Xem địa chỉ nhà riêng"</string>
+ <string name="map_work" msgid="1360474076921878088">"Xem địa chỉ cơ quan"</string>
+ <string name="map_other" msgid="3817820803587012641">"Xem địa chỉ"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Xem địa chỉ <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Trò chuyện sử dụng AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Trò chuyện sử dụng Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Trò chuyện sử dụng Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Trò chuyện sử dụng Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Trò chuyện sử dụng QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Trò chuyện sử dụng Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Trò chuyện sử dụng ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Trò chuyện sử dụng Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Trò chuyện"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"xóa"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Mở rộng hoặc thu gọn các trường tên"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Tất cả địa chỉ liên hệ"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Được gắn dấu sao"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Tùy chỉnh"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Địa chỉ liên hệ"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Tất cả địa chỉ l.hệ khác"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Tất cả địa chỉ liên hệ"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Xóa nhóm đồng bộ hóa"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Thêm nhóm đồng bộ hóa"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Nhóm khác…"</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Xóa \"<xliff:g id="GROUP">%s</xliff:g>\" khỏi đồng bộ hóa cũng sẽ xóa bất kỳ địa chỉ liên hệ nào đã được tách nhóm khỏi đồng bộ hóa."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Đang lưu tùy chọn hiển thị…"</string>
+ <string name="menu_done" msgid="796017761764190697">"Xong"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Hủy"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Nhập từ thẻ SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Hủy yêu cầu nhập <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Hủy yêu cầu xuất <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Không thể nhập/xuất vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Lỗi không xác định."</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Không thể mở \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>."</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Không thể chạy trình xuất: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Không thể xuất địa chỉ liên hệ nào."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Đã xảy ra lỗi khi xuất: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Tên tệp yêu cầu quá dài (\"<xliff:g id="FILENAME">%s</xliff:g>\")."</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Lỗi I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Không đủ bộ nhớ. Tệp có thể quá lớn."</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Không thể phân tích cú pháp vCard vì lý do không mong muốn."</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Định dạng không được hỗ trợ."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Không thể thu thập thông tin meta của (các) tệp vCard cụ thể."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Không thể nhập một hoặc nhiều tệp (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Đã xuất xong <xliff:g id="FILENAME">%s</xliff:g>."</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Quá trình xuất <xliff:g id="FILENAME">%s</xliff:g> bị hủy."</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Xuất dữ liệu liên hệ"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Không thể nhận thông tin cơ sở dữ liệu."</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Không thể xuất địa chỉ liên hệ nào. Nếu bạn có danh bạ trên điện thoại của mình, một số nhà cung cấp dữ liệu không cho phép xuất danh bạ từ điện thoại."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Trình soạn vCard không khởi động đúng."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Không thể xuất"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Không xuất được dữ liệu địa chỉ liên hệ.\nLý do: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Đang nhập <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Không thể đọc dữ liệu vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Thao tác đọc dữ liệu vCard bị hủy"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Đã nhập xong vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Quá trình nhập <xliff:g id="FILENAME">%s</xliff:g> bị hủy"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> sẽ sớm được nhập."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Tệp sẽ sớm được nhập."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Yêu cầu nhập vCard bị từ chối. Hãy thử lại sau."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> sẽ sớm được xuất."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Yêu cầu xuất vCard bị từ chối. Hãy thử lại sau."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"địa chỉ liên hệ"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Đang lưu vào bộ nhớ cache các tệp vCard sẽ được nhập vào bộ nhớ cục bộ tạm thời. Thao tác nhập thực sự sẽ sớm bắt đầu."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Không thể nhập vCard."</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"L.h nhận qua NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Xuất danh bạ?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Đang lưu vào bộ nhớ cache"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Đang nhập <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Cài đặt"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Chia sẻ liên hệ hiển thị"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Nhập/xuất danh bạ"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Nhập danh bạ"</string>
+ <string name="share_error" msgid="948429331673358107">"Không thể chia sẻ địa chỉ liên hệ này."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Tìm kiếm"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Danh bạ để hiển thị"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"DS liên hệ để hiển thị"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Mục ưa thích"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Không có địa chỉ liên hệ nào."</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Xóa DS liên hệ thường xuyên"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Chọn thẻ SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Nhập/xuất"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Số bị chặn"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">" qua <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> qua <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Xóa tìm kiếm"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-zh-rCN/donottranslate_config.xml b/res/values-zh-rCN/donottranslate_config.xml
new file mode 100644
index 0000000..b357856
--- /dev/null
+++ b/res/values-zh-rCN/donottranslate_config.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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>
+ <!-- If true, an option is shown in Display Options UI to choose a sort order -->
+ <bool name="config_sort_order_user_changeable">false</bool>
+
+ <!-- If true, the default sort order is primary (i.e. by given name) -->
+ <bool name="config_default_sort_order_primary">true</bool>
+
+ <!-- If true, an option is shown in Display Options UI to choose a name display order -->
+ <bool name="config_display_order_user_changeable">false</bool>
+
+ <!-- If true, the default sort order is primary (i.e. by given name) -->
+ <bool name="config_default_display_order_primary">true</bool>
+
+ <!-- If true, the order of name fields in the editor is primary (i.e. given name first) -->
+ <bool name="config_editor_field_order_primary">false</bool>
+</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index ffafef7..92f0287 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -27,7 +27,7 @@
<string name="shortcutActivityTitle" msgid="6642877210643565436">"选择联系人快捷方式"</string>
<string name="callShortcutActivityTitle" msgid="6065749861423648991">"选择一个可直接拨号的号码"</string>
<string name="messageShortcutActivityTitle" msgid="3084542316620335911">"选择一个可直接向其发送短信的号码"</string>
- <string name="contactInsertOrEditActivityTitle" msgid="6527505405325862674">"添加至通讯录"</string>
+ <string name="contactInsertOrEditActivityTitle" msgid="6527505405325862674">"添加到现有联系人"</string>
<string name="contactPickerActivityTitle" msgid="4301062192337417640">"选择联系人"</string>
<string name="groupMemberPickerActivityTitle" msgid="1431750793695262522">"选择"</string>
<string name="header_entry_contact_list_adapter_header_title" msgid="2436981165830115659">"创建新联系人"</string>
@@ -215,7 +215,7 @@
<string name="organization_company_and_title" msgid="6718207751363732025">"<xliff:g id="COMPANY_0">%2$s</xliff:g>,<xliff:g id="COMPANY_1">%1$s</xliff:g>"</string>
<string name="non_phone_caption" msgid="1541655052330027380">"电话号码"</string>
<string name="non_phone_add_to_contacts" msgid="6590985286250471169">"添加到通讯录"</string>
- <string name="activity_title_confirm_add_detail" msgid="4065089866210730616">"添加至联系人"</string>
+ <string name="activity_title_confirm_add_detail" msgid="4065089866210730616">"添加到现有联系人"</string>
<string name="non_phone_close" msgid="7608506439725515667">"关闭"</string>
<string name="widget_name_and_phonetic" msgid="8739586586600099979">"<xliff:g id="DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="PHONETIC_NAME">%2$s</xliff:g>)"</string>
<string name="date_year_toggle" msgid="7122002148518724139">"包含年份"</string>
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"设置默认值"</string>
<string name="clear_default" msgid="7193185801596678067">"清除默认值"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"文本已复制"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"要舍弃您所做的更改并停止修改吗?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"要舍弃更改吗?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"舍弃"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"继续修改"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"取消"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"搜索联系人"</string>
<string name="title_edit_group" msgid="8602752287270586734">"移除联系人"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"简介"</string>
<string name="send_message" msgid="8938418965550543196">"发送短信"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"正在创建个人副本..."</string>
- <string name="yesterday" msgid="6840858548955018569">"昨天"</string>
<string name="tomorrow" msgid="6241969467795308581">"明天"</string>
<string name="today" msgid="8041090779381781781">"今天"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"今天<xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"信息"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"整理列表"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"清除重复的联系人并按标签将联系人分组"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"文本已复制"</string>
+ <string name="copy_text" msgid="3257145021583508761">"复制到剪贴板"</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="8563753966926932052">"呼叫"</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="5745314124619636674">"呼叫传真号码"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"发送短信"</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="3888842199855843152">"向传真号码发送短信"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"是否清除常用联系人?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"正在清除常用联系人…"</string>
+ <string name="status_available" msgid="5586870015822828392">"在线"</string>
+ <string name="status_away" msgid="1838861100379804730">"离开"</string>
+ <string name="status_busy" msgid="9147992455450257136">"忙碌"</string>
+ <string name="contactsList" msgid="8661624236494819731">"通讯录"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"其他"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"目录"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"所有联系人"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"正在搜索..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"找到的联系人超过 <xliff:g id="COUNT">%d</xliff:g> 位。"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"没有联系人"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">找到 <xliff:g id="COUNT">%d</xliff:g> 个联系人</item>
+ <item quantity="one">找到 1 个联系人</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g>的快速联系头像"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(无姓名)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"经常联系的人"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"查看联系人"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"所有拥有电话号码的联系人"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"查看更新"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"姓名"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"昵称"</string>
+ <string name="full_name" msgid="6602579550613988977">"姓名"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"姓名拼音"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"中间名拼音"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"电话"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"电子邮件"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"地址"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"即时聊天工具"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"组织"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"关系"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"短信"</string>
+ <string name="postal_address" msgid="8765560217149624536">"地址"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"公司"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"职位"</string>
+ <string name="label_notes" msgid="8337354953278341042">"备注"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"网站"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"发送电子邮件"</string>
+ <string name="email_custom" msgid="7548003991586214105">"向<xliff:g id="CUSTOM">%s</xliff:g>发送电子邮件"</string>
+ <string name="email" msgid="5668400997660065897">"电子邮件"</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="map_home" msgid="1243547733423343982">"查看住宅地址"</string>
+ <string name="map_work" msgid="1360474076921878088">"查看单位地址"</string>
+ <string name="map_other" msgid="3817820803587012641">"查看地址"</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="description_minus_button" msgid="6908099247930477551">"删除"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"展开或折叠姓名字段"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"所有联系人"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"已加星标"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"自定义"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"联系人"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"其他所有联系人"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"所有联系人"</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_warn_remove_ungrouped" msgid="8872290721676651414">"如果您停止同步“<xliff:g id="GROUP">%s</xliff:g>”,将同时停止同步所有未分组的联系人。"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"正在保存显示选项…"</string>
+ <string name="menu_done" msgid="796017761764190697">"完成"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"取消"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"从SIM卡导入"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"要取消导入 <xliff:g id="FILENAME">%s</xliff:g> 吗?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"要取消导出 <xliff:g id="FILENAME">%s</xliff:g> 吗?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"无法取消导入/导出 vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"未知错误。"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"无法打开“<xliff:g id="FILE_NAME">%s</xliff:g>”:<xliff:g id="EXACT_REASON">%s</xliff:g>。"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"无法启动导出程序:“<xliff:g id="EXACT_REASON">%s</xliff:g>”。"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"没有可导出的联系人。"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"导出时出错:“<xliff:g id="EXACT_REASON">%s</xliff:g>”。"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"指定的文件名过长(“<xliff:g id="FILENAME">%s</xliff:g>”)。"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O 错误"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"内存不足。该文件可能过大。"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"由于意外原因而无法解析 vCard。"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"该格式不受支持。"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"无法收集指定的 vCard 文件的元信息。"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"一个或多个文件无法导入 (%s)。"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"导出 <xliff:g id="FILENAME">%s</xliff:g> 已完成。"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"已取消导出 <xliff:g id="FILENAME">%s</xliff:g>。"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"正在导出联系人数据"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"无法获取数据库信息。"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"没有可导出的联系人。如果您的手机上确实存有联系人信息,可能是某些数据服务提供商不允许从手机中导出联系人。"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard 制作程序未正确启动。"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"无法导出"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"未导出联系人数据。\n原因:“<xliff:g id="FAIL_REASON">%s</xliff:g>”"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"正在导入<xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"无法读取 vCard 数据"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"已取消读取 vCard 数据"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"导入 vCard <xliff:g id="FILENAME">%s</xliff:g> 已完成"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"已取消导入 <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> 将在稍后导入。"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"系统稍后就会导入该文件。"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard 导入请求遭拒,请稍后重试。"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> 将在稍后导出。"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard 导出请求遭拒,请稍后重试。"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"联系人"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"正在将 vCard 缓存到本地临时存储设备。实际导入操作即将开始。"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"无法导入 vCard。"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"已通过 NFC 收到联系人信息"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"要导出联系人吗?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"正在缓存..."</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"正在导入第 <xliff:g id="CURRENT_NUMBER">%s</xliff:g> 个(共 <xliff:g id="TOTAL_NUMBER">%s</xliff:g> 个)联系人:<xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"设置"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"分享可见的联系人"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"导入/导出联系人"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"导入联系人"</string>
+ <string name="share_error" msgid="948429331673358107">"无法分享此联系人。"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"搜索"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"要显示的联系人"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"要显示的联系人"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"收藏"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"没有联系人。"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"清除常用联系人"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"选择SIM卡"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"导入/导出"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"已屏蔽的号码"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"来源:<xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"时间:<xliff:g id="DATE">%1$s</xliff:g>,来源:<xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"清除搜索内容"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 03c4931..544d6c0 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"設為預設"</string>
<string name="clear_default" msgid="7193185801596678067">"清除預設值"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"文字已複製"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"要捨棄變更並停止編輯嗎?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"丟棄變更?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"捨棄"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"繼續編輯"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"取消"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"搜尋聯絡人"</string>
<string name="title_edit_group" msgid="8602752287270586734">"移除聯絡人"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"關於"</string>
<string name="send_message" msgid="8938418965550543196">"傳送訊息"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"正在建立個人副本…"</string>
- <string name="yesterday" msgid="6840858548955018569">"昨天"</string>
<string name="tomorrow" msgid="6241969467795308581">"明天"</string>
<string name="today" msgid="8041090779381781781">"今天"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"今天<xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"訊息"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"整理名單"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"清理重複項目並依照標籤將聯絡人分組"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"文字已複製"</string>
+ <string name="copy_text" msgid="3257145021583508761">"複製到剪貼簿"</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="8563753966926932052">"致電"</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="5745314124619636674">"致電其他傳真"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"傳送簡訊至"</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="3888842199855843152">"傳送簡訊至傳真"</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>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"清除常用聯絡人?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"正在清除常用聯絡人…"</string>
+ <string name="status_available" msgid="5586870015822828392">"在線"</string>
+ <string name="status_away" msgid="1838861100379804730">"離開"</string>
+ <string name="status_busy" msgid="9147992455450257136">"忙碌"</string>
+ <string name="contactsList" msgid="8661624236494819731">"通訊錄"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"其他"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"名錄"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"全部聯絡人"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"正在搜尋..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"找到超過 <xliff:g id="COUNT">%d</xliff:g> 位聯絡人。"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"沒有聯絡人"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">找到 <xliff:g id="COUNT">%d</xliff:g> 位聯絡人</item>
+ <item quantity="one">找到 1 位聯絡人</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"快速聯絡<xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(沒有名稱)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"常用聯絡人"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"查看聯絡人資料"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"所有附有電話號碼的聯絡人"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"查看更新"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"名稱"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"暱稱"</string>
+ <string name="full_name" msgid="6602579550613988977">"名稱"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"姓名拼音"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"中間名 (拼音)"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"電話"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"電子郵件"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"地址"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"機構"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"關係"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"短訊"</string>
+ <string name="postal_address" msgid="8765560217149624536">"地址"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"公司"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"標題"</string>
+ <string name="label_notes" msgid="8337354953278341042">"備註"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"網站"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"電郵"</string>
+ <string name="email_custom" msgid="7548003991586214105">"傳送電郵至 <xliff:g id="CUSTOM">%s</xliff:g> 的信箱"</string>
+ <string name="email" msgid="5668400997660065897">"電郵"</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="map_home" msgid="1243547733423343982">"查看住宅地址"</string>
+ <string name="map_work" msgid="1360474076921878088">"查看公司地址"</string>
+ <string name="map_other" msgid="3817820803587012641">"檢視地址"</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="description_minus_button" msgid="6908099247930477551">"刪除"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"展開或收合名稱欄位"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"所有聯絡人"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"已加星號"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"自訂"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"聯絡人"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"所有其他聯絡人"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"全部聯絡人"</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_warn_remove_ungrouped" msgid="8872290721676651414">"如果從同步設定中移除「<xliff:g id="GROUP">%s</xliff:g>」群組,也會移除任何未分組的聯絡人。"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"正在儲存顯示選項…"</string>
+ <string name="menu_done" msgid="796017761764190697">"完成"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"取消"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"從 SIM 卡匯入"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"要取消匯入「<xliff:g id="FILENAME">%s</xliff:g>」的操作嗎?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"要取消匯出「<xliff:g id="FILENAME">%s</xliff:g>」的操作嗎?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"無法取消匯入/匯出 vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"不明錯誤。"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"無法開啟「<xliff:g id="FILE_NAME">%s</xliff:g>」:<xliff:g id="EXACT_REASON">%s</xliff:g>。"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"無法啟動匯出程式:「<xliff:g id="EXACT_REASON">%s</xliff:g>」。"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"沒有聯絡人資料可以匯出。"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"匯出時發生錯誤:「<xliff:g id="EXACT_REASON">%s</xliff:g>」。"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"要求的檔案名稱過長 (「<xliff:g id="FILENAME">%s</xliff:g>」)。"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"匯入/匯出錯誤"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"記憶體不足,檔案可能過大。"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"由於未預期的原因,無法剖析 vCard。"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"不支援這種格式。"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"無法從指定的 vCard 檔案收集中繼資料。"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"無法匯入一個或多個檔案 (%s)。"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"匯出 <xliff:g id="FILENAME">%s</xliff:g> 完畢。"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"已取消匯出「<xliff:g id="FILENAME">%s</xliff:g>」的操作。"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"正在匯出聯絡人資料"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"無法取得資料庫資訊。"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"沒有聯絡人資料可以匯出。如果您的手機中確實存有聯絡人資料,則可能是部分資料提供者不允許您將聯絡人資料從手機中匯出。"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard 編輯器並未正確啟動。"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"無法匯出"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"聯絡人資料未匯出。\n原因:「<xliff:g id="FAIL_REASON">%s</xliff:g>」"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"匯入 <xliff:g id="NAME">%s</xliff:g> 中"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"無法讀取 vCard 資料"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"已取消讀取 vCard 資料的操作"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"已完成匯入 vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"已取消匯入「<xliff:g id="FILENAME">%s</xliff:g>」的操作"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> 將在稍後匯入。"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"稍後即將匯入檔案。"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard 匯入要求已被拒,請稍後再試。"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> 將在稍後匯出。"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard 匯出要求已被拒,請稍後再試。"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"聯絡人"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"正在將 vCard 資料快取至本機暫存空間,隨即將開始實際的匯入操作。"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"無法匯入 vCard。"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"已透過 NFC 收到聯絡人資訊"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"要匯出聯絡人資料嗎?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"快取中"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"正在匯入第 <xliff:g id="CURRENT_NUMBER">%s</xliff:g> 個:<xliff:g id="NAME">%s</xliff:g>,共 <xliff:g id="TOTAL_NUMBER">%s</xliff:g> 個"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"設定"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"分享正常顯示的聯絡人"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"匯入/匯出聯絡人資料"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"匯入通訊錄"</string>
+ <string name="share_error" msgid="948429331673358107">"無法分享這位聯絡人的資料。"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"搜尋"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"要顯示的聯絡人"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"要顯示的聯絡人"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"我的最愛"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"沒有聯絡人。"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"清除常用聯絡人"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"選取 SIM 卡"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"匯入/匯出"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"已封鎖的號碼"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"透過 <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> (透過 <xliff:g id="SOURCE">%2$s</xliff:g>)"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"清除搜尋"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-zh-rTW/donottranslate_config.xml b/res/values-zh-rTW/donottranslate_config.xml
new file mode 100644
index 0000000..b357856
--- /dev/null
+++ b/res/values-zh-rTW/donottranslate_config.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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>
+ <!-- If true, an option is shown in Display Options UI to choose a sort order -->
+ <bool name="config_sort_order_user_changeable">false</bool>
+
+ <!-- If true, the default sort order is primary (i.e. by given name) -->
+ <bool name="config_default_sort_order_primary">true</bool>
+
+ <!-- If true, an option is shown in Display Options UI to choose a name display order -->
+ <bool name="config_display_order_user_changeable">false</bool>
+
+ <!-- If true, the default sort order is primary (i.e. by given name) -->
+ <bool name="config_default_display_order_primary">true</bool>
+
+ <!-- If true, the order of name fields in the editor is primary (i.e. given name first) -->
+ <bool name="config_editor_field_order_primary">false</bool>
+</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 58f3aac..bf76e7f 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"設為預設值"</string>
<string name="clear_default" msgid="7193185801596678067">"清除預設值"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"文字已複製"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"確定要捨棄變更並結束編輯嗎?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"要捨棄變更嗎?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"捨棄"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"繼續編輯"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"取消"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"搜尋聯絡人"</string>
<string name="title_edit_group" msgid="8602752287270586734">"移除聯絡人"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"關於"</string>
<string name="send_message" msgid="8938418965550543196">"傳送簡訊"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"正在建立個人副本…"</string>
- <string name="yesterday" msgid="6840858548955018569">"昨天"</string>
<string name="tomorrow" msgid="6241969467795308581">"明天"</string>
<string name="today" msgid="8041090779381781781">"今天"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"今天<xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"訊息"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"管理您的清單"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"清除重複的聯絡人並按標籤將聯絡人分組"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"文字已複製"</string>
+ <string name="copy_text" msgid="3257145021583508761">"複製到剪貼簿"</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="8563753966926932052">"通話"</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="5745314124619636674">"撥打傳真"</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>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <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="806127844607642331">"傳送簡訊"</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="3888842199855843152">"傳送簡訊至傳真"</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">"向多媒體訊息電話號碼傳送文字簡訊"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"清除常用聯絡人?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"正在清除常用聯絡人…"</string>
+ <string name="status_available" msgid="5586870015822828392">"線上"</string>
+ <string name="status_away" msgid="1838861100379804730">"離開"</string>
+ <string name="status_busy" msgid="9147992455450257136">"忙碌"</string>
+ <string name="contactsList" msgid="8661624236494819731">"聯絡人"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"其他"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"目錄"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"所有聯絡人"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"搜尋中…"</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"找到 <xliff:g id="COUNT">%d</xliff:g> 位以上的聯絡人。"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"沒有聯絡人"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="other">找到 <xliff:g id="COUNT">%d</xliff:g> 位聯絡人</item>
+ <item quantity="one">找到 1 位聯絡人</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"<xliff:g id="NAME">%1$s</xliff:g>的快速聯絡人相片"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(無姓名)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"常用聯絡人"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"查看聯絡人"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"所有包含電話號碼的聯絡人資訊"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"查看更新"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"姓名"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"暱稱"</string>
+ <string name="full_name" msgid="6602579550613988977">"姓名"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <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" msgid="4259595234312430484">"姓名拼音"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"中間名 (拼音)"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"電話"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"電子郵件"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"地址"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"即時訊息"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"機構"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"關係"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"簡訊"</string>
+ <string name="postal_address" msgid="8765560217149624536">"地址"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"公司"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"職稱"</string>
+ <string name="label_notes" msgid="8337354953278341042">"附註"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"網站"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <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="3454004077967657109">"傳送電子郵件"</string>
+ <string name="email_custom" msgid="7548003991586214105">"傳送電子郵件至<xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"傳送電子郵件"</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="map_home" msgid="1243547733423343982">"檢視住家地址"</string>
+ <string name="map_work" msgid="1360474076921878088">"檢視公司地址"</string>
+ <string name="map_other" msgid="3817820803587012641">"檢視地址"</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="description_minus_button" msgid="6908099247930477551">"刪除"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"展開或收合名稱欄位"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"所有聯絡人"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"已加星號"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"自訂"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"聯絡人"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"所有其他聯絡人"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"所有聯絡人"</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_warn_remove_ungrouped" msgid="8872290721676651414">"如果停用「<xliff:g id="GROUP">%s</xliff:g>」群組的同步處理設定,也會停止同步處理任何未分組的聯絡人。"</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"正在儲存顯示選項…"</string>
+ <string name="menu_done" msgid="796017761764190697">"完成"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"取消"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"從 SIM 卡匯入"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"確定要取消匯入 <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"確定要取消匯出 <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"無法取消匯入/匯出 vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"不明錯誤。"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"無法開啟「<xliff:g id="FILE_NAME">%s</xliff:g>」:<xliff:g id="EXACT_REASON">%s</xliff:g>。"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"無法啟動匯出程式:<xliff:g id="EXACT_REASON">%s</xliff:g>。"</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"沒有可匯出的聯絡人。"</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"匯出時發生錯誤:<xliff:g id="EXACT_REASON">%s</xliff:g>。"</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"要求的檔案名稱過長 (<xliff:g id="FILENAME">%s</xliff:g>)。"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"I/O 錯誤"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"記憶體不足,檔案可能過大。"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"由於意外因素,導致無法剖析 vCard。"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"不支援此格式。"</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"無法從指定的 vCard 檔案收集中繼資料。"</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"無法匯入一或多個檔案 (%s)。"</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"已完成 <xliff:g id="FILENAME">%s</xliff:g> 匯出作業。"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"已取消匯出 <xliff:g id="FILENAME">%s</xliff:g>。"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"正在匯出聯絡人資料"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"無法取得資料庫資訊。"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"沒有可匯出的聯絡人。如果您的手機中確實有聯絡人資料,那麼可能是部分資料提供者不允許您將聯絡人資料從手機中匯出。"</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"vCard 編輯器並未正確啟動。"</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"無法匯出"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"聯絡人資料未匯出。\n原因:<xliff:g id="FAIL_REASON">%s</xliff:g>"</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"正在匯入 <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"無法讀取 vCard 資料"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"已取消讀取 vCard 資料"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"已完成匯入 vCard 的 <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"已取消匯入 <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"<xliff:g id="FILENAME">%s</xliff:g> 將在稍後匯入。"</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"稍候即將匯入該檔案。"</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"vCard 匯入要求遭到拒絕,請稍後再試。"</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"<xliff:g id="FILENAME">%s</xliff:g> 將在稍後匯出。"</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"vCard 匯出要求遭到拒絕,請稍後再試。"</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"聯絡人"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"正在將 vCard 資料快取至本機暫存空間,隨即將啟動實際的匯入作業。"</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"無法匯入 vCard。"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"已透過 NFC 收到聯絡人資訊"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"確定要匯出聯絡人?"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"快取中"</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"正在匯入第 <xliff:g id="CURRENT_NUMBER">%s</xliff:g> 筆資料:<xliff:g id="NAME">%s</xliff:g>,共 <xliff:g id="TOTAL_NUMBER">%s</xliff:g> 筆資料"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"設定"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"分享正常顯示的聯絡人"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"匯入/匯出聯絡人"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"匯入聯絡人"</string>
+ <string name="share_error" msgid="948429331673358107">"無法分享這位聯絡人。"</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"搜尋"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"要顯示的聯絡人"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"要顯示的聯絡人"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"我的收藏"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"沒有聯絡人。"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"清除常用聯絡人"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"選取 SIM 卡"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"匯入/匯出"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"已封鎖的號碼"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"透過 <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> (透過 <xliff:g id="SOURCE">%2$s</xliff:g>)"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"清除搜尋"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 81745fd..02c06db 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -232,9 +232,9 @@
<string name="set_default" msgid="4417505153468300351">"Hlela okuzenzakalelayo"</string>
<string name="clear_default" msgid="7193185801596678067">"Sula okuzenzakalelayo"</string>
<string name="toast_text_copied" msgid="5143776250008541719">"Umbhalo okopishiwe"</string>
- <string name="cancel_confirmation_dialog_message" msgid="5058226498605989285">"Lahla izinguquko zakho bese uyeke ukuhlela?"</string>
+ <string name="cancel_confirmation_dialog_message" msgid="9008214737653278989">"Lahla ushintsho?"</string>
<string name="cancel_confirmation_dialog_cancel_editing_button" msgid="3057023972074640671">"Lahla"</string>
- <string name="cancel_confirmation_dialog_keep_editing_button" msgid="7737724111972855348">"Qhubeka uhlela"</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button" msgid="3316573928085916146">"Khansela"</string>
<string name="call_type_and_date" msgid="747163730039311423">"<xliff:g id="CALL_TYPE">%1$s</xliff:g> <xliff:g id="CALL_SHORT_DATE">%2$s</xliff:g>"</string>
<string name="enter_contact_name" msgid="4594274696120278368">"Sesha oxhumana nabo"</string>
<string name="title_edit_group" msgid="8602752287270586734">"Susa oxhumana nabo"</string>
@@ -259,7 +259,6 @@
<string name="about_card_title" msgid="2920942314212825637">"Mayelana"</string>
<string name="send_message" msgid="8938418965550543196">"Thumela umlayezo"</string>
<string name="toast_making_personal_copy" msgid="288549957278065542">"Idala ikhophi yomuntu siqu"</string>
- <string name="yesterday" msgid="6840858548955018569">"Izolo"</string>
<string name="tomorrow" msgid="6241969467795308581">"Kusasa"</string>
<string name="today" msgid="8041090779381781781">"Namhlanje"</string>
<string name="today_at_time_fmt" msgid="605665249491030460">"Namhlanje ngo-<xliff:g id="TIME_INTERVAL">%s</xliff:g>"</string>
@@ -342,4 +341,334 @@
<string name="permission_explanation_subheader_SMS" msgid="1904552086449525567">"Imilayezo"</string>
<string name="hamburger_feature_highlight_header" msgid="7442308698936786415">"Hlela uhlu lwakho"</string>
<string name="hamburger_feature_highlight_body" msgid="6268711111318172098">"Hlanza izimpinda noxhumana nabo beqembu ngelebulli"</string>
+ <string name="toast_text_copied" msgid="5143776250008541719">"Umbhalo okopishiwe"</string>
+ <string name="copy_text" msgid="3257145021583508761">"Kopisha ku-clipboard"</string>
+ <string name="call_custom" msgid="7756571794763171802">"Shayela <xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="call_home" msgid="1990519474420545392">"Shayela ekhaya"</string>
+ <string name="call_mobile" msgid="7502236805487609178">"Shayela ifoni"</string>
+ <string name="call_work" msgid="5328785911463744028">"Shayela emsebenzini"</string>
+ <string name="call_fax_work" msgid="7467763592359059243">"Shayela ifeksi yasemsebenzini"</string>
+ <string name="call_fax_home" msgid="8342175628887571876">"Shayela ifeksi yasekhaya"</string>
+ <string name="call_pager" msgid="9003902812293983281">"Shayela isicingo"</string>
+ <string name="call_other" msgid="8563753966926932052">"Shayela"</string>
+ <string name="call_callback" msgid="1910165691349426858">"Shayela ukuphinda ushaye"</string>
+ <string name="call_car" msgid="3280537320306436445">"Shayela imoto"</string>
+ <string name="call_company_main" msgid="6105120947138711257">"Shayela isisekelo senkampani"</string>
+ <string name="call_isdn" msgid="1541590690193403411">"Shayela i-ISDN"</string>
+ <string name="call_main" msgid="6082900571803441339">"Shayela isisekelo"</string>
+ <string name="call_other_fax" msgid="5745314124619636674">"Shayela ifeksi"</string>
+ <string name="call_radio" msgid="8296755876398357063">"Shayela umsakazo"</string>
+ <string name="call_telex" msgid="2223170774548648114">"Shayela i-telex"</string>
+ <string name="call_tty_tdd" msgid="8951266948204379604">"Shayela i-TTY/TDD"</string>
+ <string name="call_work_mobile" msgid="8707874281430105394">"Shayela ifoni yasemsebenzini"</string>
+ <string name="call_work_pager" msgid="3419348514157949008">"Shayela isicingo sasemsebenzini"</string>
+ <string name="call_assistant" msgid="2141641383068514308">"Shayela<xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="call_mms" msgid="6274041545876221437">"Shayela i-MMS"</string>
+ <!-- no translation found for call_by_shortcut (2566802538698913124) -->
+ <skip />
+ <string name="sms_custom" msgid="5932736853732191825">" Okubhaliwe<xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="sms_home" msgid="7524332261493162995">"Ikhaya lombhalo"</string>
+ <string name="sms_mobile" msgid="5200107250451030769">"Umbhalo wefoni"</string>
+ <string name="sms_work" msgid="2269624156655267740">"Bhalela emsebenzini"</string>
+ <string name="sms_fax_work" msgid="8028189067816907075">"Bhalela ifeksi yasemsebenzini"</string>
+ <string name="sms_fax_home" msgid="9204042076306809634">"Bhalela ifeksi yasekhaya"</string>
+ <string name="sms_pager" msgid="7730404569637015192">"Bhalela isicingo"</string>
+ <string name="sms_other" msgid="806127844607642331">"Umbhalo"</string>
+ <string name="sms_callback" msgid="5004824430094288752">"Bhalela ukuphinda ukushayela"</string>
+ <string name="sms_car" msgid="7444227058437359641">"Bhalela imoto"</string>
+ <string name="sms_company_main" msgid="118970873419678087">"Bhalela isisekelo senkampani"</string>
+ <string name="sms_isdn" msgid="8153785037515047845">"Bhalela i-ISDN"</string>
+ <string name="sms_main" msgid="8621625784504541679">"Bhalela isisekelo"</string>
+ <string name="sms_other_fax" msgid="3888842199855843152">"Ifeksi yombhalo"</string>
+ <string name="sms_radio" msgid="3329166673433967820">"Bhalela umsakazo"</string>
+ <string name="sms_telex" msgid="9034802430065267848">"Bhalela i-telex"</string>
+ <string name="sms_tty_tdd" msgid="6782284969132531532">"Bhalela i-TTY/TDD"</string>
+ <string name="sms_work_mobile" msgid="2459939960512702560">"Bhalela ifoni yasemsebenzini"</string>
+ <string name="sms_work_pager" msgid="5566924423316960597">"Bhalela isicingo sasemsebenzini"</string>
+ <string name="sms_assistant" msgid="2773424339923116234">"Okubhaliwe<xliff:g id="ASSISTANT">%s</xliff:g>"</string>
+ <string name="sms_mms" msgid="4069352461380762677">"Bhala i-MMS"</string>
+ <!-- no translation found for sms_by_shortcut (7741770672976099517) -->
+ <skip />
+ <!-- no translation found for description_video_call (7120921378651700947) -->
+ <skip />
+ <string name="clearFrequentsConfirmation_title" msgid="766292372438450432">"Sula oxhumana nabo njalo?"</string>
+ <!-- no translation found for clearFrequentsConfirmation (2270554975938265734) -->
+ <skip />
+ <string name="clearFrequentsProgress_title" msgid="5157001637482794212">"Isula oxhumana nabo njalo…"</string>
+ <string name="status_available" msgid="5586870015822828392">"Yatholakala"</string>
+ <string name="status_away" msgid="1838861100379804730">"Akekho"</string>
+ <string name="status_busy" msgid="9147992455450257136">"Matasa"</string>
+ <string name="contactsList" msgid="8661624236494819731">"Othi tana nabo"</string>
+ <string name="local_invisible_directory" msgid="6046691709127661065">"Okunye"</string>
+ <string name="directory_search_label" msgid="1887759056597975053">"Uhla lwemibhalo"</string>
+ <!-- no translation found for directory_search_label_work (8618292129829443176) -->
+ <skip />
+ <string name="local_search_label" msgid="2551177578246113614">"Bonke oxhumana nabo"</string>
+ <string name="search_results_searching" msgid="3984833028938569930">"Iyasesha..."</string>
+ <string name="foundTooManyContacts" msgid="5163335650920020220">"kutholakele <xliff:g id="COUNT">%d</xliff:g>edlula"</string>
+ <string name="listFoundAllContactsZero" msgid="922980883593159444">"Abekho oxhumana nabo"</string>
+ <plurals name="searchFoundContacts" formatted="false" msgid="7223023725334884618">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> abatholakele</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> abatholakele</item>
+ </plurals>
+ <string name="description_quick_contact_for" msgid="6737516415168327789">"Oxhumene naye ngokushesha ku <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="missing_name" msgid="8745511583852904385">"(alikho igama)"</string>
+ <string name="favoritesFrequentContacted" msgid="6184232487472425690">"Abathintwa njalo"</string>
+ <string name="description_view_contact_detail" msgid="9133251213656414807">"Buka othintana naye"</string>
+ <string name="list_filter_phones" msgid="735313795643493365">"Bonke othintana nabo kanye nezinombolo zabo zocingo"</string>
+ <!-- no translation found for list_filter_phones_work (1470173699551475015) -->
+ <skip />
+ <string name="view_updates_from_group" msgid="1782685984905600034">"Buka Okwenziwe Kabusha"</string>
+ <!-- no translation found for account_phone (7128032778471187553) -->
+ <skip />
+ <string name="nameLabelsGroup" msgid="2034640839640477827">"Igama"</string>
+ <string name="nicknameLabelsGroup" msgid="2891682101053358010">"Igama lokudlala"</string>
+ <string name="full_name" msgid="6602579550613988977">"Igama"</string>
+ <!-- no translation found for name_given (4280790853455320619) -->
+ <skip />
+ <!-- no translation found for name_family (7466985689626017037) -->
+ <skip />
+ <string name="name_prefix" msgid="59756378548779822">"Qamba isiqalo"</string>
+ <string name="name_middle" msgid="8467433655992690326">"Igama"</string>
+ <string name="name_suffix" msgid="3855278445375651441">"Qamba isijobelelo"</string>
+ <string name="name_phonetic" msgid="4259595234312430484">"Igama leFonethikhi"</string>
+ <!-- no translation found for name_phonetic_given (8723179018384187631) -->
+ <skip />
+ <string name="name_phonetic_middle" msgid="8643721493320405200">"Igama lefonethikhi"</string>
+ <!-- no translation found for name_phonetic_family (2640133663656011626) -->
+ <skip />
+ <string name="phoneLabelsGroup" msgid="6468091477851199285">"Ifoni"</string>
+ <string name="emailLabelsGroup" msgid="8389931313045344406">"I-imeyli"</string>
+ <string name="postalLabelsGroup" msgid="3487738141112589324">"Ikheli"</string>
+ <string name="imLabelsGroup" msgid="3898238486262614027">"IM"</string>
+ <string name="organizationLabelsGroup" msgid="2478611760751832035">"Inhlangano"</string>
+ <string name="relationLabelsGroup" msgid="1854373894284572781">"Ubudlelwano"</string>
+ <!-- no translation found for eventLabelsGroup (7960408705307831289) -->
+ <skip />
+ <string name="sms" msgid="1756857139634224222">"Umlayezo wombhalo"</string>
+ <string name="postal_address" msgid="8765560217149624536">"Ikheli"</string>
+ <string name="ghostData_company" msgid="5414421120553765775">"Inkampani"</string>
+ <string name="ghostData_title" msgid="7496735200318496110">"Isihloko"</string>
+ <string name="label_notes" msgid="8337354953278341042">"Imibhalo"</string>
+ <!-- no translation found for label_sip_address (7252153678613978127) -->
+ <skip />
+ <string name="websiteLabelsGroup" msgid="4202998982804009261">"Iwebhusayithi"</string>
+ <!-- no translation found for groupsLabel (7000816729542098972) -->
+ <skip />
+ <string name="email_home" msgid="8573740658148184279">"Ikhaya le-imeyili"</string>
+ <string name="email_mobile" msgid="2042889209787989814">"Imeyla ifoni"</string>
+ <string name="email_work" msgid="2807430017302722689">"Imeyila emsebenzini"</string>
+ <string name="email_other" msgid="3454004077967657109">"I-imeyli"</string>
+ <string name="email_custom" msgid="7548003991586214105">"I-imeyili<xliff:g id="CUSTOM">%s</xliff:g>"</string>
+ <string name="email" msgid="5668400997660065897">"I-imeyili"</string>
+ <string name="postal_street" msgid="8133143961580058972">"Isitaladi"</string>
+ <string name="postal_pobox" msgid="4431938829180269821">"PO box"</string>
+ <string name="postal_neighborhood" msgid="1450783874558956739">"Indawo yasekhaya"</string>
+ <string name="postal_city" msgid="6597491300084895548">"Idolobha"</string>
+ <string name="postal_region" msgid="6045263193478437672">"Idolobha"</string>
+ <string name="postal_postcode" msgid="572136414136673751">"Ikhodi ye-ZIP"</string>
+ <string name="postal_country" msgid="7638264508416368690">"Izwe"</string>
+ <string name="map_home" msgid="1243547733423343982">"Vuka ikheli lasekhaya"</string>
+ <string name="map_work" msgid="1360474076921878088">"Buka ikheli lasemsebenzini"</string>
+ <string name="map_other" msgid="3817820803587012641">"Buka ikheli"</string>
+ <string name="map_custom" msgid="6184363799976265281">"Buka <xliff:g id="CUSTOM">%s</xliff:g> ikheli"</string>
+ <string name="chat_aim" msgid="2588492205291249142">"Xoxa usebenzisa i-AIM"</string>
+ <string name="chat_msn" msgid="8041633440091073484">"Xoxa usebenzisa i-Windows Live"</string>
+ <string name="chat_yahoo" msgid="6629211142719943666">"Xoxa usebenzisa i-Yahoo"</string>
+ <string name="chat_skype" msgid="1210045020427480566">"Xoxa usebenzisa i-Skype"</string>
+ <string name="chat_qq" msgid="4294637812847719693">"Xoxa usebenzisa i-QQ"</string>
+ <string name="chat_gtalk" msgid="981575737258117697">"Xoxa usebenzisa i-Google Talk"</string>
+ <string name="chat_icq" msgid="8438405386153745775">"Xoxa usebenzisa i-ICQ"</string>
+ <string name="chat_jabber" msgid="7561444230307829609">"Xoxa usebenzisa i-Jabber"</string>
+ <string name="chat" msgid="9025361898797412245">"Xoxa"</string>
+ <string name="description_minus_button" msgid="6908099247930477551">"susa"</string>
+ <string name="expand_collapse_name_fields_description" msgid="8682630859539604311">"Nweba noma goqa izinkambu zegama"</string>
+ <!-- no translation found for expand_collapse_phonetic_name_fields_description (3306777588073354509) -->
+ <skip />
+ <string name="list_filter_all_accounts" msgid="8908683398914322369">"Bonke othintana nabo"</string>
+ <string name="list_filter_all_starred" msgid="5031734941601931356">"Okunenkanyezi"</string>
+ <string name="list_filter_customize" msgid="4789963356004169321">"Enza ngendlela oyifisayo"</string>
+ <string name="list_filter_single" msgid="5871400283515893087">"Othintana nabo"</string>
+ <string name="display_ungrouped" msgid="6885954210243119591">"Bonke Abanye Othintana Nabo"</string>
+ <string name="display_all_contacts" msgid="2031647544742889505">"Bonke oxhumana nabo"</string>
+ <string name="menu_sync_remove" msgid="3266725887008450161">"Khipha iqembu lokuvumelanisa"</string>
+ <string name="dialog_sync_add" msgid="8267045393119375803">"Ngeza iqembu lokuvumelanisa"</string>
+ <string name="display_more_groups" msgid="2682547080423434170">"Amanye amaqembu..."</string>
+ <string name="display_warn_remove_ungrouped" msgid="8872290721676651414">"Iyasusa \"<xliff:g id="GROUP">%s</xliff:g>\" kokuvumelanisiwe izophinde isuse nanoma ibaphi oxhumana nabo abangelona iqoqo."</string>
+ <string name="savingDisplayGroups" msgid="2133152192716475939">"Ilondoloza izinketho zokubonisa"</string>
+ <string name="menu_done" msgid="796017761764190697">"Kwenziwe"</string>
+ <string name="menu_doNotSave" msgid="58593876893538465">"Khansela"</string>
+ <!-- no translation found for listCustomView (1840624396582117590) -->
+ <skip />
+ <!-- no translation found for dialog_new_contact_account (4969619718062454756) -->
+ <skip />
+ <string name="import_from_sim" msgid="3859272228033941659">"Ngenisa kusuka kwikhadi le-SIM"</string>
+ <!-- no translation found for import_from_sim_summary (5815105584445743740) -->
+ <skip />
+ <!-- no translation found for import_from_sim_summary_no_number (880612418352086012) -->
+ <skip />
+ <!-- no translation found for import_from_vcf_file (5304572242183878086) -->
+ <skip />
+ <string name="cancel_import_confirmation_message" msgid="3929951040347726757">"Misa ukulndwa kwe <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_export_confirmation_message" msgid="1995462401949262638">"Misa ukulandwa kwe <xliff:g id="FILENAME">%s</xliff:g>?"</string>
+ <string name="cancel_vcard_import_or_export_failed" msgid="6139900383366166706">"Yehlulekile ukukhansela ukungenisa/thekelisa i-vCard"</string>
+ <string name="fail_reason_unknown" msgid="1714092345030570863">"Iphutha elingaziwa"</string>
+ <string name="fail_reason_could_not_open_file" msgid="2067725459821997463">"Ayikwazi ukuvula \"<xliff:g id="FILE_NAME">%s</xliff:g>\": <xliff:g id="EXACT_REASON">%s</xliff:g>"</string>
+ <string name="fail_reason_could_not_initialize_exporter" msgid="707260459259688510">"Ayikwazanga ukuqalisa isithekelisi: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\""</string>
+ <string name="fail_reason_no_exportable_contact" msgid="8728506011371262065">"Abekho othintana nabo abathumelekayo."</string>
+ <!-- no translation found for missing_required_permission (5865884842972833120) -->
+ <skip />
+ <string name="fail_reason_error_occurred_during_export" msgid="3018855323913649063">"Kube khona iphutha ngesikhathi kuthunyelwa: \"<xliff:g id="EXACT_REASON">%s</xliff:g>\"."</string>
+ <string name="fail_reason_too_long_filename" msgid="3393764245254738333">"Igama lefayela elidingekayo lide kakhulu (\"<xliff:g id="FILENAME">%s</xliff:g>\")"</string>
+ <string name="fail_reason_io_error" msgid="6748358842976073255">"Iphutha le-I/O"</string>
+ <string name="fail_reason_low_memory_during_import" msgid="875222757734882898">"Isikhala asanele (kungenzeka ifayela ibe nkulu kakhulu)"</string>
+ <string name="fail_reason_vcard_parse_error" msgid="888263542360355784">"Yehlulekile ukunqunta i-vCard ngokwesizathu esingalindelekile"</string>
+ <string name="fail_reason_not_supported" msgid="8219562769267148825">"Ifomethi ayisekelwe."</string>
+ <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="6427931733267328564">"Yehlulekile ukuqoqa ulwazi lwemetha lwefayela noma amafayela e-vCard."</string>
+ <string name="fail_reason_failed_to_read_files" msgid="5823434810622484922">"Ifayela elilodwa noma amafayela angaphezulu ehlulekile ukungenisa (%s)."</string>
+ <string name="exporting_vcard_finished_title" msgid="4767045779458185251">"Iqedile ukuthumela kwenye indawo <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <!-- no translation found for exporting_vcard_finished_title_fallback (6060472638008218274) -->
+ <skip />
+ <!-- no translation found for exporting_vcard_finished_toast (1739055986856453882) -->
+ <skip />
+ <!-- no translation found for touch_to_share_contacts (4882485525268469736) -->
+ <skip />
+ <string name="exporting_vcard_canceled_title" msgid="2652222370493306887">"Ukulandwa <xliff:g id="FILENAME">%s</xliff:g> kumisiwe"</string>
+ <string name="exporting_contact_list_title" msgid="9072240631534457415">"Ithekelisa idatha yothintana naye"</string>
+ <!-- no translation found for exporting_contact_list_message (3367949209642931952) -->
+ <skip />
+ <string name="composer_failed_to_get_database_infomation" msgid="1765944280846236723">"Yehlulekile ukuthola ulwazi lwemininingo egciniwe"</string>
+ <string name="composer_has_no_exportable_contact" msgid="3296493229040294335">"Abekho oxhuana nabo abathuelekayo. Um unabo oxhuana nabo ocingweni lwakho, banye abahlinzeki be-data kungenzeka bangavumeli labo oxhuana nabo ukuthi bathunyelwe kolunye ucingo."</string>
+ <string name="composer_not_initialized" msgid="2321648986367005254">"Umqambi we-Vcard akazange aqale ngendlela efanele."</string>
+ <string name="exporting_contact_failed_title" msgid="4892358112409576342">"Yehlulekile ukuthumela"</string>
+ <string name="exporting_contact_failed_message" msgid="4938527850142003141">"Imininingwane yoxhumana naye ayizange ithunyelwe.\nIsizathu: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
+ <string name="importing_vcard_description" msgid="4245275224298571351">"Iyangenisa <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="reading_vcard_failed_title" msgid="4251647443358422855">"Yehlulekile ukufunda imininingo ye-vCard"</string>
+ <string name="reading_vcard_canceled_title" msgid="1925216585981542019">"Ukufundwa kwe-Vcard kumisiwe"</string>
+ <string name="importing_vcard_finished_title" msgid="3341541727268747967">"Iqedile ukungenisa i-vCard <xliff:g id="FILENAME">%s</xliff:g>"</string>
+ <string name="importing_vcard_canceled_title" msgid="2147475978165599336">"Ukulandwa <xliff:g id="FILENAME">%s</xliff:g> kukhanseliwe"</string>
+ <string name="vcard_import_will_start_message" msgid="2804911199145873396">"i-<xliff:g id="FILENAME">%s</xliff:g> izongeniswa maduze nje."</string>
+ <string name="vcard_import_will_start_message_with_default_name" msgid="1022969530654129470">"Ifayela izongeniswa maduze nje."</string>
+ <string name="vcard_import_request_rejected_message" msgid="2890471184508516011">"Isicelo sokungenisa i-vCard sinqatshelwe. Sicela uzame futhi emva kwesikhathi."</string>
+ <string name="vcard_export_will_start_message" msgid="2210241345252081463">"i-<xliff:g id="FILENAME">%s</xliff:g> izothekeliswa maduze nje."</string>
+ <!-- no translation found for vcard_export_will_start_message_fallback (6553826997490909749) -->
+ <skip />
+ <!-- no translation found for contacts_export_will_start_message (8538705791417534431) -->
+ <skip />
+ <string name="vcard_export_request_rejected_message" msgid="2844874826431327531">"Isicelo sokuthekelisa i-vCard sinqatshelwe. Sicela uzame futhi emva kwesikhathi."</string>
+ <string name="vcard_unknown_filename" msgid="7171709890959915954">"othintana nabo"</string>
+ <string name="caching_vcard_message" msgid="4926308675041506756">"Ifihla i-vCard/ama-vCard endaweni yokugcina eseduze. Ukulandwa kwangampela kuzoqala khona maduze."</string>
+ <string name="vcard_import_failed" msgid="5223531255894842406">"Yehlulekile ukulanda i-vCard"</string>
+ <string name="nfc_vcard_file_name" msgid="2823095213265993609">"Othintana naye utholakale nge-NFC"</string>
+ <string name="confirm_export_title" msgid="6834385377255286349">"Thekelisa othintana nabo"</string>
+ <string name="caching_vcard_title" msgid="1226272312940516605">"Ukulondoloza isikhashana..."</string>
+ <string name="progress_notifier_message" msgid="2311011466908220528">"Ingenisa <xliff:g id="CURRENT_NUMBER">%s</xliff:g>/<xliff:g id="TOTAL_NUMBER">%s</xliff:g>: <xliff:g id="NAME">%s</xliff:g>"</string>
+ <!-- no translation found for export_to_vcf_file (4407527157056120858) -->
+ <skip />
+ <!-- no translation found for display_options_sort_list_by (7028809117272018712) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_given_name (2778421332815687873) -->
+ <skip />
+ <!-- no translation found for display_options_sort_by_family_name (2684905041926954793) -->
+ <skip />
+ <!-- no translation found for display_options_view_names_as (6514632499276563482) -->
+ <skip />
+ <!-- no translation found for display_options_view_given_name_first (3616004640258761473) -->
+ <skip />
+ <!-- no translation found for display_options_view_family_name_first (956445100777296467) -->
+ <skip />
+ <!-- no translation found for settings_accounts (350219740670774576) -->
+ <skip />
+ <!-- no translation found for default_editor_account (699591683362420991) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_title (6957956139306960211) -->
+ <skip />
+ <!-- no translation found for sync_contact_metadata_dialog_title (6192335951588820553) -->
+ <skip />
+ <!-- no translation found for settings_my_info_title (1534272456405343119) -->
+ <skip />
+ <!-- no translation found for set_up_profile (7370213843590143771) -->
+ <skip />
+ <!-- no translation found for setting_about (7014388749752042863) -->
+ <skip />
+ <string name="activity_title_settings" msgid="5464130076132770781">"Izilungiselelo"</string>
+ <string name="share_visible_contacts" msgid="890150378880783797">"Yabelana nothintana nabo ababonakalayo"</string>
+ <!-- no translation found for share_visible_contacts_failure (7324717548166915560) -->
+ <skip />
+ <!-- no translation found for share_favorite_contacts (4280926751003081042) -->
+ <skip />
+ <!-- no translation found for share_contacts (8109287987498711664) -->
+ <skip />
+ <!-- no translation found for share_contacts_failure (1216431977330560559) -->
+ <skip />
+ <string name="dialog_import_export" msgid="4360648034889921624">"Ngenisa/Thekelisa othintana nabo"</string>
+ <string name="dialog_import" msgid="2431698729761448759">"Ngenisa othintana nabo"</string>
+ <string name="share_error" msgid="948429331673358107">"Lona oxhumana naye ngeke ukwazi ukwabelana ngaye."</string>
+ <!-- no translation found for no_contact_to_share (1276397530378323033) -->
+ <skip />
+ <string name="menu_search" msgid="9147752853603483719">"Sesha"</string>
+ <string name="menu_contacts_filter" msgid="2165153460860262501">"Othintana nabo abazoboniswa"</string>
+ <string name="activity_title_contacts_filter" msgid="8275542497615516969">"Othintana nabo abazoboniswa"</string>
+ <!-- no translation found for custom_list_filter (2105275443109077687) -->
+ <skip />
+ <!-- no translation found for menu_custom_filter_save (2679793632208086460) -->
+ <skip />
+ <!-- no translation found for hint_findContacts (7128627979899070325) -->
+ <skip />
+ <string name="contactsFavoritesLabel" msgid="8417039765586853670">"Izintandokazi"</string>
+ <string name="listTotalAllContactsZero" msgid="5513001821794568211">"Abekho othintana nabo"</string>
+ <string name="menu_clear_frequents" msgid="7688250191932838833">"Sula oxhumana nabo njalo"</string>
+ <string name="menu_select_sim" msgid="3603578201960504010">"Khetha ikhadi le-SIM"</string>
+ <!-- no translation found for menu_accounts (1424330057450189074) -->
+ <skip />
+ <string name="menu_import_export" msgid="26217871113229507">"Ngenisa/Thekelisa"</string>
+ <string name="menu_blocked_numbers" msgid="5272951629083025995">"Izinombolo ezivinjiwe"</string>
+ <string name="contact_status_update_attribution" msgid="752179367353018597">"nge <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
+ <string name="contact_status_update_attribution_with_date" msgid="7358045508107825068">"<xliff:g id="DATE">%1$s</xliff:g> nge- <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
+ <!-- no translation found for action_menu_back_from_search (8793348588949233348) -->
+ <skip />
+ <string name="description_clear_search" msgid="688023606766232904">"Sula usesho"</string>
+ <!-- no translation found for settings_contact_display_options_title (4890258244494248687) -->
+ <skip />
+ <!-- no translation found for select_account_dialog_title (5478489655696599219) -->
+ <skip />
+ <!-- no translation found for set_default_account (4311613760725609801) -->
+ <skip />
+ <!-- no translation found for select_phone_account_for_calls (3810607744451014540) -->
+ <skip />
+ <!-- no translation found for call_with_a_note (8389827628360791676) -->
+ <skip />
+ <!-- no translation found for call_subject_hint (3637498418381454511) -->
+ <skip />
+ <!-- no translation found for send_and_call_button (7740295432834590737) -->
+ <skip />
+ <!-- no translation found for call_subject_limit (4545212901205397669) -->
+ <skip />
+ <!-- no translation found for call_subject_type_and_number (7667188212129152558) -->
+ <skip />
+ <!-- no translation found for tab_title_with_unread_items (7682024005130747825) -->
+ <!-- no translation found for about_build_version (1765533099416999801) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses (6479990452352919641) -->
+ <skip />
+ <!-- no translation found for about_open_source_licenses_summary (57418386931763994) -->
+ <skip />
+ <!-- no translation found for about_privacy_policy (3705518622499152626) -->
+ <skip />
+ <!-- no translation found for about_terms_of_service (4642400812150296723) -->
+ <skip />
+ <!-- no translation found for activity_title_licenses (5467767062737708066) -->
+ <skip />
+ <!-- no translation found for url_open_error_toast (452592089815420457) -->
+ <skip />
+ <!-- no translation found for account_filter_view_checked (6696859503887762213) -->
+ <skip />
+ <!-- no translation found for account_filter_view_not_checked (2248684521205038389) -->
+ <skip />
+ <!-- no translation found for description_search_video_call (5841525580339803272) -->
+ <skip />
+ <!-- no translation found for description_delete_contact (53835657343783663) -->
+ <skip />
+ <!-- no translation found for description_no_name_header (8884991311595943271) -->
+ <skip />
</resources>
diff --git a/res/values/animation_constants.xml b/res/values/animation_constants.xml
new file mode 100644
index 0000000..39f6ba6
--- /dev/null
+++ b/res/values/animation_constants.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2014 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>
+ <integer name="floating_action_button_animation_duration">175</integer>
+</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 86c46fc..e979611 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -49,4 +49,71 @@
<attr name="layout_widePaddingRight" format="dimension"/>
</declare-styleable>
+ <declare-styleable name="Theme">
+ <attr name="android:textColorSecondary" />
+ </declare-styleable>
+
+ <declare-styleable name="ContactsDataKind">
+ <!-- Mime-type handled by this mapping. -->
+ <attr name="android:mimeType" />
+ <!-- Icon used to represent data of this kind. -->
+ <attr name="android:icon" />
+ <!-- Column in data table that summarizes this data. -->
+ <attr name="android:summaryColumn" />
+ <!-- Column in data table that contains details for this data. -->
+ <attr name="android:detailColumn" />
+ <!-- Flag indicating that detail should be built from SocialProvider. -->
+ <attr name="android:detailSocialSummary" />
+ <!-- Resource representing the term "All Contacts" (e.g. "All Friends" or
+ "All connections"). Optional (Default is "All Contacts"). -->
+ <attr name="android:allContactsName" />
+ </declare-styleable>
+
+ <declare-styleable name="ContactListItemView">
+ <attr name="list_item_height" format="dimension"/>
+ <attr name="list_section_header_height" format="dimension"/>
+ <attr name="activated_background" format="reference"/>
+ <attr name="section_header_background" format="reference"/>
+ <attr name="list_item_padding_top" format="dimension"/>
+ <attr name="list_item_padding_right" format="dimension"/>
+ <attr name="list_item_padding_bottom" format="dimension"/>
+ <attr name="list_item_padding_left" format="dimension"/>
+ <attr name="list_item_gap_between_image_and_text" format="dimension"/>
+ <attr name="list_item_gap_between_indexer_and_image" format="dimension"/>
+ <attr name="list_item_gap_between_label_and_data" format="dimension"/>
+ <attr name="list_item_presence_icon_margin" format="dimension"/>
+ <attr name="list_item_presence_icon_size" format="dimension"/>
+ <attr name="list_item_photo_size" format="dimension"/>
+ <attr name="list_item_profile_photo_size" format="dimension"/>
+ <attr name="list_item_prefix_highlight_color" format="color"/>
+ <attr name="list_item_background_color" format="color"/>
+ <attr name="list_item_header_text_indent" format="dimension"/>
+ <attr name="list_item_header_text_color" format="color"/>
+ <attr name="list_item_header_text_size" format="dimension"/>
+ <attr name="list_item_header_height" format="dimension"/>
+ <attr name="list_item_name_text_color" format="color"/>
+ <attr name="list_item_name_text_size" format="dimension"/>
+ <attr name="list_item_text_indent" format="dimension"/>
+ <attr name="list_item_text_offset_top" format="dimension"/>
+ <attr name="list_item_avatar_offset_top" format="dimension"/>
+ <attr name="list_item_data_width_weight" format="integer"/>
+ <attr name="list_item_label_width_weight" format="integer"/>
+ <attr name="list_item_video_call_icon_size" format="dimension"/>
+ <attr name="list_item_video_call_icon_margin" format="dimension"/>
+ </declare-styleable>
+
+ <declare-styleable name="ContactBrowser">
+ <attr name="contact_browser_list_padding_left" format="dimension"/>
+ <attr name="contact_browser_list_padding_right" format="dimension"/>
+ <attr name="contact_browser_background" format="reference"/>
+ </declare-styleable>
+
+ <declare-styleable name="ProportionalLayout">
+ <attr name="direction" format="string"/>
+ <attr name="ratio" format="float"/>
+ </declare-styleable>
+
+ <declare-styleable name="Favorites">
+ <attr name="favorites_padding_bottom" format="dimension"/>
+ </declare-styleable>
</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index f5bf4cc..37ea0ba 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -83,4 +83,178 @@
<!-- Color of hamburger icon in promo -->
<color name="hamburger_feature_highlight_inner_color">#00ffffff</color>
+
+ <!-- Background color corresponding to the holo list 9-patch. -->
+ <color name="holo_list_background_color">#eeeeee</color>
+
+ <color name="focus_color">#44ff0000</color>
+
+ <!-- Color of ripples used for views with dark backgrounds -->
+ <color name="ripple_material_dark">#a0ffffff</color>
+
+ <!-- Divider color for header separator -->
+ <color name="primary_text_color">#363636</color>
+
+ <color name="secondary_text_color">@color/dialtacts_secondary_text_color</color>
+
+ <!-- Text color for section header. -->
+ <color name="section_header_text_color">@color/dialtacts_theme_color</color>
+
+ <!-- Divider color for header separator -->
+ <color name="main_header_separator_color">#AAAAAA</color>
+
+ <!-- Divider color for header separator -->
+ <color name="secondary_header_separator_color">#D0D0D0</color>
+
+ <!-- Color of the theme of the People app -->
+ <color name="people_app_theme_color">#363636</color>
+
+ <!-- Color of the theme of the Dialer app -->
+ <color name="dialtacts_theme_color">#0288d1</color>
+
+ <!-- Color of image view placeholder. -->
+ <color name="image_placeholder">#DDDDDD</color>
+
+ <!-- Primary text color in the Phone app -->
+ <color name="dialtacts_primary_text_color">#333333</color>
+
+ <!-- Secondary text color in the Phone app -->
+ <color name="dialtacts_secondary_text_color">#737373</color>
+
+ <!-- Color of the semi-transparent shadow box on contact tiles -->
+ <color name="contact_tile_shadow_box_color">#7F000000</color>
+
+ <!-- Color of the status message for starred contacts in the People app -->
+ <color name="people_contact_tile_status_color">#CCCCCC</color>
+
+ <color name="shortcut_overlay_text_background">#7f000000</color>
+
+ <color name="textColorIconOverlay">#fff</color>
+ <color name="textColorIconOverlayShadow">#000</color>
+
+ <!-- Background colors for LetterTileDrawables. This set of colors is a subset of
+ https://spec.googleplex.com/quantumpalette#extended which passes Google Accessibility
+ Requirements for the color in question on white with >= 3.0 contrast. We used
+ http://leaverou.github.io/contrast-ratio/#white-on-%23db4437 to double-check the contrast.
+
+ These colors are also used by MaterialColorMapUtils to generate primary activity colors.
+ -->
+ <array name="letter_tile_colors">
+ <item>#DB4437</item>
+ <item>#E91E63</item>
+ <item>#9C27B0</item>
+ <item>#673AB7</item>
+ <item>#3F51B5</item>
+ <item>#4285F4</item>
+ <item>#039BE5</item>
+ <item>#0097A7</item>
+ <item>#009688</item>
+ <item>#0F9D58</item>
+ <item>#689F38</item>
+ <item>#EF6C00</item>
+ <item>#FF5722</item>
+ <item>#757575</item>
+ </array>
+
+ <!-- Darker versions of letter_tile_colors, two shades darker. These colors are used
+ for settings secondary activity colors. -->
+ <array name="letter_tile_colors_dark">
+ <item>#C53929</item>
+ <item>#C2185B</item>
+ <item>#7B1FA2</item>
+ <item>#512DA8</item>
+ <item>#303F9F</item>
+ <item>#3367D6</item>
+ <item>#0277BD</item>
+ <item>#006064</item>
+ <item>#00796B</item>
+ <item>#0B8043</item>
+ <item>#33691E</item>
+ <item>#E65100</item>
+ <item>#E64A19</item>
+ <item>#424242</item>
+ </array>
+
+ <!-- The default color used for tinting photos when no color can be extracted via Palette,
+ this is Blue Grey 500 -->
+ <color name="quickcontact_default_photo_tint_color">#607D8B</color>
+ <!-- The default secondary color when no color can be extracted via Palette,
+ this is Blue Grey 700 -->
+ <color name="quickcontact_default_photo_tint_color_dark">#455A64</color>
+
+
+ <color name="letter_tile_default_color">#cccccc</color>
+
+ <color name="letter_tile_font_color">#ffffff</color>
+
+ <!-- Background color of action bars. Ensure this stays in sync with packages/Telephony
+ actionbar_background_color. -->
+ <color name="actionbar_background_color">#0fc6dc</color>
+ <!-- Color for icons in the actionbar -->
+ <color name="actionbar_icon_color">#ffffff</color>
+ <!-- Darker version of the actionbar color. Used for the status bar and navigation bar colors. -->
+ <color name="actionbar_background_color_dark">#008aa1</color>
+
+ <color name="tab_ripple_color">@color/tab_accent_color</color>
+ <color name="tab_accent_color">#ffffff</color>
+ <color name="tab_selected_underline_color">@color/tab_accent_color</color>
+ <color name="tab_unread_count_background_color">#700f4b70</color>
+
+ <!-- Color of the title to the Frequently Contacted section -->
+ <color name="frequently_contacted_title_color">@color/actionbar_background_color</color>
+
+ <!-- Color of action bar text. Ensure this stays in sync with packages/Telephony
+ phone_settings_actionbar_text_color-->
+ <color name="actionbar_text_color">#ffffff</color>
+ <!-- 54% black for icons -->
+ <color name="actionbar_icon_color_grey">#8C000000</color>
+ <!-- 87% black for actionbar text -->
+ <color name="actionbar_text_color_black">#DF000000</color>
+ <!-- Solid grey for status bar overlay-->
+ <color name="actionbar_color_grey_solid">#777777</color>
+ <color name="actionbar_unselected_text_color">#a6ffffff</color>
+
+ <!-- Text color of the search box text as entered by user -->
+ <color name="searchbox_text_color">#000000</color>
+ <!-- Background color of the search box -->
+ <color name="searchbox_background_color">#ffffff</color>
+
+ <color name="searchbox_hint_text_color">#66000000</color>
+ <color name="searchbox_icon_tint">@color/searchbox_hint_text_color</color>
+
+ <color name="search_shortcut_icon_color">@color/dialtacts_theme_color</color>
+
+ <!-- Color of the background of the contact detail and editor pages -->
+ <color name="background_primary">#f9f9f9</color>
+ <color name="contact_all_list_background_color">#FFFFFF</color>
+
+ <!-- Text color used for character counter when the max limit has been exceeded -->
+ <color name="call_subject_limit_exceeded">#d1041c</color>
+
+ <!-- Tint color for the call subject history icon. -->
+ <color name="call_subject_history_icon">#000000</color>
+
+ <!-- Divider line on the call subject dialog. -->
+ <color name="call_subject_divider">#d8d8d8</color>
+
+ <!-- Text color for the SEND & CALL button on the call subject dialog. -->
+ <color name="call_subject_button">#00c853</color>
+
+ <!-- Background color for the call subject history view. -->
+ <color name="call_subject_history_background">#ffffff</color>
+ <color name="search_video_call_icon_tint">@color/searchbox_hint_text_color</color>
+
+ <!-- Text color for an action in a snackbar. -->
+ <color name="snackbar_action_text">#40c4ff</color>
+ <!-- Background color for a snackbar. -->
+ <color name="snackbar_background">#333333</color>
+
+ <!-- Color of account/custom filters -->
+ <color name="account_filter_text_color">@color/actionbar_text_color_black</color>
+ <color name="custom_filter_divider">#dbdbdb</color>
+
+ <color name="material_star_pink">#f50057</color>
+
+ <!-- Primary text color in Contacts app -->
+ <color name="contacts_text_color">#333333</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a73e449..d355021 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -321,4 +321,171 @@
<!-- Margin b/w add account button and import contacts button for no account empty view -->
<dimen name="contacts_no_account_buttons_margin">8dp</dimen>
+
+ <!-- Padding between the action bar's bottom edge and the first header
+ in contacts/group lists. -->
+ <dimen name="list_header_extra_top_padding">0dip</dimen>
+
+ <dimen name="list_section_divider_min_height">32dip</dimen>
+
+ <dimen name="directory_header_extra_top_padding">18dp</dimen>
+ <dimen name="directory_header_extra_bottom_padding">8dp</dimen>
+ <dimen name="directory_header_left_padding">16dp</dimen>
+
+ <!-- Horizontal padding in between contact tiles -->
+ <dimen name="contact_tile_divider_padding">23dip</dimen>
+ <!-- Horizontal whitespace (both padding and margin) before the first tile and after the last tile -->
+ <dimen name="contact_tile_start_end_whitespace">16dip</dimen>
+
+ <!-- Left and right padding for a contact detail item -->
+ <dimen name="detail_item_side_margin">16dip</dimen>
+
+ <!-- ContactTile Layouts -->
+ <!--
+ Use sp instead of dip so that the shadowbox heights can all scale uniformly
+ when the font size is scaled for accessibility purposes
+ -->
+ <dimen name="contact_tile_shadowbox_height">48sp</dimen>
+
+ <!-- For contact filter setting screens -->
+ <dimen name="contact_filter_left_margin">8dp</dimen>
+ <dimen name="contact_filter_right_margin">16dip</dimen>
+ <dimen name="contact_filter_item_min_height">48dip</dimen>
+ <dimen name="contact_filter_icon_size">32dip</dimen>
+ <dimen name="contact_filter_list_item_height">56dp</dimen>
+ <dimen name="contact_filter_list_item_padding_start">16dp</dimen>
+ <!-- contact_filter_indicator is the arrow in expandable list view -->
+ <dimen name="contact_filter_indicator_padding_start">6dp</dimen>
+ <dimen name="contact_filter_indicator_padding_end">46dp</dimen>
+ <dimen name="contact_filter_action_button_width">72dp</dimen>
+
+ <!-- Padding to be used between a visible scrollbar and the contact list -->
+ <dimen name="list_visible_scrollbar_padding">32dip</dimen>
+
+ <dimen name="contact_browser_list_header_icon_left_margin">16dp</dimen>
+ <dimen name="contact_browser_list_header_icon_right_margin">14dp</dimen>
+ <dimen name="contact_browser_list_header_icon_left_margin_alt">18dp</dimen>
+ <dimen name="contact_browser_list_header_icon_right_margin_alt">16dp</dimen>
+ <dimen name="contact_browser_list_header_left_margin">16dip</dimen>
+ <dimen name="contact_browser_list_header_right_margin">@dimen/list_visible_scrollbar_padding</dimen>
+ <dimen name="contact_browser_list_item_text_indent">8dip</dimen>
+ <dimen name="contact_browser_list_header_height">48dp</dimen>
+ <dimen name="contact_browser_list_header_icon_size">24dp</dimen>
+ <dimen name="contact_browser_list_header_icon_size_alt">20dp</dimen>
+ <dimen name="contact_browser_list_header_text_margin">10dp</dimen>
+ <!-- Width of a contact list item section header. -->
+ <dimen name="contact_list_section_header_width">56dp</dimen>
+
+ <!-- Size of the shortcut icon. 0dip means: use the system default -->
+ <dimen name="shortcut_icon_size">0dip</dimen>
+
+ <!-- Text size of shortcut icon overlay text -->
+ <dimen name="shortcut_overlay_text_size">12dp</dimen>
+
+ <!-- Extra vertical padding for darkened background behind shortcut icon overlay text -->
+ <dimen name="shortcut_overlay_text_background_padding">1dp</dimen>
+
+ <!-- Width of height of an icon from a third-party app in the networks section of the contact card. -->
+ <dimen name="detail_network_icon_size">40dp</dimen>
+
+ <!-- Empty message margins -->
+ <dimen name="empty_message_top_margin">48dip</dimen>
+
+ <!-- contact browser list margins -->
+ <dimen name="contact_browser_list_item_text_size">16sp</dimen>
+ <dimen name="contact_browser_list_item_photo_size">40dp</dimen>
+ <dimen name="contact_browser_list_item_gap_between_image_and_text">15dp</dimen>
+ <dimen name="contact_browser_list_item_gap_between_indexer_and_image">16dp</dimen>
+ <dimen name="contact_browser_list_top_margin">12dp</dimen>
+
+ <!-- Dimensions for "No contacts" string in PhoneFavoriteFragment for the All contacts
+ with phone numbers section
+ -->
+ <dimen name="contact_phone_list_empty_description_size">20sp</dimen>
+ <dimen name="contact_phone_list_empty_description_padding">10dip</dimen>
+
+ <!-- Dimensions for contact letter tiles -->
+ <dimen name="tile_letter_font_size">40dp</dimen>
+ <dimen name="tile_letter_font_size_small">20dp</dimen>
+ <dimen name="tile_divider_width">1dp</dimen>
+ <item name="letter_to_tile_ratio" type="dimen">67%</item>
+
+ <!-- Height of the floating action button -->
+ <dimen name="floating_action_button_height">56dp</dimen>
+ <!-- Width of the floating action button -->
+ <dimen name="floating_action_button_width">56dp</dimen>
+ <!-- Corner radius of the floating action button -->
+ <dimen name="floating_action_button_radius">28dp</dimen>
+ <!-- Z translation of the floating action button -->
+ <dimen name="floating_action_button_translation_z">8dp</dimen>
+ <!-- Padding to be applied to the bottom of lists to make space for the floating action
+ button -->
+ <dimen name="floating_action_button_list_bottom_padding">88dp</dimen>
+ <!-- Right margin of the floating action button -->
+ <dimen name="floating_action_button_margin_right">16dp</dimen>
+ <!-- Bottom margin of the floating action button -->
+ <dimen name="floating_action_button_margin_bottom">16dp</dimen>
+ <!-- Offset of bottom margin of the floating action button used when dialpad is up -->
+ <dimen name="floating_action_button_dialpad_margin_bottom_offset">4dp</dimen>
+
+ <!-- Height of the selection indicator of a tab. -->
+ <dimen name="tab_selected_underline_height">2dp</dimen>
+ <!-- Size of text in tabs. -->
+ <dimen name="tab_text_size">14sp</dimen>
+ <dimen name="tab_elevation">2dp</dimen>
+ <dimen name="tab_unread_count_background_size">16dp</dimen>
+ <dimen name="tab_unread_count_background_radius">2dp</dimen>
+ <dimen name="tab_unread_count_margin_left">10dp</dimen>
+ <dimen name="tab_unread_count_margin_top">2dp</dimen>
+ <dimen name="tab_unread_count_text_size">12sp</dimen>
+ <dimen name="tab_unread_count_text_padding">2dp</dimen>
+
+ <!-- Padding around the icon in the search box. -->
+ <dimen name="search_box_icon_margin">4dp</dimen>
+ <!-- Size of the icon (voice search, back arrow) in the search box. -->
+ <dimen name="search_box_icon_size">56dp</dimen>
+ <!-- Size of the close icon.-->
+ <dimen name="search_box_close_icon_size">56dp</dimen>
+ <!-- Padding around the close button. It's visible size without padding is 24dp. -->
+ <dimen name="search_box_close_icon_padding">16dp</dimen>
+ <!-- End margin of the back arrow icon in the search box -->
+ <dimen name="search_box_navigation_icon_margin">8dp</dimen>
+ <!-- Left margin of the text field in the search box. -->
+ <dimen name="search_box_text_left_margin">8dp</dimen>
+ <!-- Search box text size -->
+ <dimen name="search_text_size">16sp</dimen>
+
+ <item name="close_icon_alpha" format="float" type="dimen">0.54</item>
+
+ <!-- Size of the close icon in selection bar.-->
+ <dimen name="selection_bar_close_icon_size">56dp</dimen>
+
+ <!-- Top margin for the Frequently Contacted section title -->
+ <dimen name="frequently_contacted_title_top_margin_when_first_row">16dp</dimen>
+ <!-- Top margin for the Frequently Contacted section title, when the title is the first
+ item in the list -->
+ <dimen name="frequently_contacted_title_top_margin">57dp</dimen>
+
+ <dimen name="frequently_contacted_title_text_size">24sp</dimen>
+
+ <!-- Size of icon for contacts number shortcuts -->
+ <dimen name="search_shortcut_radius">40dp</dimen>
+
+ <dimen name="contact_list_card_elevation">2dp</dimen>
+
+ <!-- Padding used around the periphery of the call subject dialog, as well as in between the
+ items. -->
+ <dimen name="call_subject_dialog_margin">20dp</dimen>
+ <!-- Padding used between lines of text in the call subject dialog. -->
+ <dimen name="call_subject_dialog_between_line_margin">8dp</dimen>
+ <!-- Size of the contact photo in the call subject dialog. -->
+ <dimen name="call_subject_dialog_contact_photo_size">50dp</dimen>
+ <!-- Margin above the edit text in the call subject dialog. -->
+ <dimen name="call_subject_dialog_edit_spacing">60dp</dimen>
+ <!-- Size of primary text in the call subject dialog. -->
+ <dimen name="call_subject_dialog_primary_text_size">16sp</dimen>
+ <!-- Size of secondary text in the call subject dialog. -->
+ <dimen name="call_subject_dialog_secondary_text_size">14sp</dimen>
+ <!-- Row padding for call subject history items. -->
+ <dimen name="call_subject_history_item_padding">15dp</dimen>
</resources>
diff --git a/res/values/donottranslate_config.xml b/res/values/donottranslate_config.xml
index bfe7880..8668159 100644
--- a/res/values/donottranslate_config.xml
+++ b/res/values/donottranslate_config.xml
@@ -39,4 +39,81 @@
<!-- File Authority for AOSP Contacts files -->
<string name="contacts_file_provider_authority">com.android.contacts.files</string>
+ <!-- Flag indicating whether Contacts app is allowed to import contacts -->
+ <bool name="config_allow_import_from_vcf_file">true</bool>
+
+ <!-- If true, an option is shown in Display Options UI to choose a sort order -->
+ <bool name="config_sort_order_user_changeable">true</bool>
+
+ <!-- If true, the default sort order is primary (i.e. by given name) -->
+ <bool name="config_default_sort_order_primary">true</bool>
+
+ <!-- If true, an option is shown in Display Options UI to choose a name display order -->
+ <bool name="config_display_order_user_changeable">true</bool>
+
+ <!-- If true, the default sort order is primary (i.e. by given name) -->
+ <bool name="config_default_display_order_primary">true</bool>
+
+ <!-- If true, the order of name fields in the editor is primary (i.e. given name first) -->
+ <bool name="config_editor_field_order_primary">true</bool>
+
+ <!-- If true, an option is shown in Display Options UI to choose a default account -->
+ <bool name="config_default_account_user_changeable">true</bool>
+
+ <!-- Contacts preferences key for contact editor default account -->
+ <string name="contact_editor_default_account_key">ContactEditorUtils_default_account</string>
+
+ <!-- Contacts preferences key for contact editor anything saved -->
+ <string name="contact_editor_anything_saved_key">ContactEditorUtils_anything_saved</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>
+
+ <!-- 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>
+
+ <!-- Prefix of exported VCard file -->
+ <string name="config_export_file_prefix" translatable="false"></string>
+
+ <!-- Suffix of exported VCard file. Attached before an extension -->
+ <string name="config_export_file_suffix" translatable="false"></string>
+
+ <!-- Extension for exported VCard files -->
+ <string name="config_export_file_extension">vcf</string>
+
+ <!-- The filename that is suggested that users use when exporting vCards. Should include the .vcf extension. -->
+ <string name="exporting_vcard_filename" translatable="false">contacts.vcf</string>
+
+ <!-- Minimum number of exported VCard file index -->
+ <integer name="config_export_file_min_index">1</integer>
+
+ <!-- Maximum number of exported VCard file index -->
+ <integer name="config_export_file_max_index">99999</integer>
+
+ <!-- The list (separated by ',') of extensions should be checked in addition to
+ 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" translatable="false"></string>
+
+ <!-- If true, enable the "import contacts from SIM" feature if the device
+ has an appropriate SIM or ICC card.
+ Setting this flag to false in a resource overlay allows you to
+ entirely disable SIM import on a per-product basis. -->
+ <bool name="config_allow_sim_import">true</bool>
+
+ <!-- Flag indicating whether Contacts app is allowed to export contacts -->
+ <bool name="config_allow_export">true</bool>
+
+ <!-- Flag indicating whether Contacts app is allowed to share contacts with devices outside -->
+ <bool name="config_allow_share_contacts">true</bool>
+
+ <string name="pref_build_version_key">pref_build_version</string>
+ <string name="pref_open_source_licenses_key">pref_open_source_licenses</string>
+ <string name="pref_privacy_policy_key">pref_privacy_policy</string>
+ <string name="pref_terms_of_service_key">pref_terms_of_service</string>
+
+ <string name="star_sign">\u2605</string>
</resources>
diff --git a/res/values/ids.xml b/res/values/ids.xml
index f5649d9..0808496 100644
--- a/res/values/ids.xml
+++ b/res/values/ids.xml
@@ -52,4 +52,29 @@
<!-- Menu group ID for the contact filters -->
<item type="id" name="nav_filters_items" />
+
+ <!-- For vcard.ImportVCardActivity -->
+ <item type="id" name="dialog_cache_vcard"/>
+ <item type="id" name="dialog_error_with_message"/>
+
+ <!-- For vcard.CancelActivity -->
+ <item type="id" name="dialog_cancel_confirmation"/>
+ <item type="id" name="dialog_cancel_failed"/>
+
+ <!-- For ExportVCardActivity -->
+ <item type="id" name="dialog_exporting_vcard"/>
+ <item type="id" name="dialog_fail_to_export_with_reason"/>
+
+ <!-- For Debug Purpose -->
+ <item type="id" name="cliv_name_textview"/>
+ <item type="id" name="cliv_phoneticname_textview"/>
+ <item type="id" name="cliv_label_textview"/>
+ <item type="id" name="cliv_data_view"/>
+
+ <!-- For tag ids used by ContactPhotoManager to tag views with contact details -->
+ <item type="id" name="tag_display_name"/>
+ <item type="id" name="tag_identifier"/>
+ <item type="id" name="tag_contact_type"/>
+
+ <item type="id" name="menu_save"/>
</resources>
diff --git a/res/values/integers.xml b/res/values/integers.xml
index 60034e5..9ef7810 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -36,4 +36,27 @@
<!-- Top margin ratio for the image for empty contacts view-->
<integer name="contacts_no_account_empty_image_margin_divisor">2</integer>
+
+ <!-- Determines the number of columns in a ContactTileRow in the favorites tab -->
+ <integer name="contact_tile_column_count_in_favorites">2</integer>
+ <integer name="contact_tile_column_count_in_favorites_new">3</integer>
+
+ <!-- The number of characters in the snippet before we need to tokenize and ellipse. -->
+ <integer name="snippet_length_before_tokenize">30</integer>
+
+ <!-- Layout weight of space elements in contact list view.
+ Default to 0 to indicate no padding-->
+ <integer name="contact_list_space_layout_weight">0</integer>
+ <!-- Layout weight of card in contact list view.
+ Default to 0 to indicate no padding -->
+ <integer name="contact_list_card_layout_weight">0</integer>
+
+ <!-- Duration of the animations on the call subject dialog. -->
+ <integer name="call_subject_animation_duration">250</integer>
+
+ <!-- A big number to make sure "About contacts" always showing at the bottom of Settings.-->
+ <integer name="about_contacts_order_number">100</integer>
+
+ <!-- Duration of the animations when a contact list loads. -->
+ <integer name="lists_on_load_animation_duration">190</integer>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7a81940..9f1dd90 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -369,6 +369,9 @@
<!-- Toast displayed when saving a label failed [CHAR LIMIT=70] -->
<string name="groupSavedErrorToast">Couldn\'t save label changes.</string>
+ <!-- Message displayed when creating a group with the same name as an existing group -->
+ <string name="groupExistsErrorMessage">That label already exists</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">1 contact with phone number</item>
@@ -632,9 +635,6 @@
Initiates a contact import dialog [CHAR LIMIT=128] -->
<string name="contacts_unavailable_import_contacts">Import</string>
- <!-- Title of the dialog that allows creation of a contact label [CHAR LIMIT=50] -->
- <string name="create_group_dialog_title">Create new label</string>
-
<!-- An item in the popup list of labels that triggers creation of a contact label [CHAR LIMIT=128] -->
<string name="create_group_item_label">Create new…</string>
@@ -663,7 +663,7 @@
<string name="toast_text_copied">Text copied</string>
<!-- Contents of the alert dialog when the user hits the Cancel button in the editor [CHAR LIMIT=128] -->
- <string name="cancel_confirmation_dialog_message">Discard your changes and quit editing?</string>
+ <string name="cancel_confirmation_dialog_message">Discard changes?</string>
<!-- Positive button text for the cancel editing confirmation dialog.
Pushing this button indicates that the user wishes to discard the changes they have already
@@ -673,7 +673,7 @@
<!-- Negative button text for the cancel editing confirmation dialog.
Pushing this button indicates that the user wishes to continue editing
and return to the editor [CHAR LIMIT=30] -->
- <string name="cancel_confirmation_dialog_keep_editing_button">Keep editing</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button">Cancel</string>
<!-- Description of a call log entry, made of a call type and a date -->
<string name="call_type_and_date">
@@ -751,8 +751,7 @@
<!-- Toast that appears when you are copying a directory contact into your personal contacts -->
<string name="toast_making_personal_copy">Creating a personal copy…</string>
- <!-- Timestamp string for interactions from yesterday. [CHAR LIMIT=40] -->
- <string name="yesterday">Yesterday</string>
+ <!-- Timestamp string for interactions from tomorrow. [CHAR LIMIT=40] -->
<string name="tomorrow">Tomorrow</string>
<!-- Timestamp string for interactions from today. [CHAR LIMIT=40] -->
<string name="today">Today</string>
@@ -964,4 +963,843 @@
<string name="hamburger_feature_highlight_header">Organize your list</string>
<!-- The body text for hamburger promo [CHAR LIMIT=200]-->
<string name="hamburger_feature_highlight_body">Clean up duplicates & group contacts by label</string>
+
+ <!-- Toast shown when text is copied to the clipboard [CHAR LIMIT=64] -->
+ <string name="toast_text_copied">Text copied</string>
+ <!-- Option displayed in context menu to copy long pressed item to clipboard [CHAR LIMIT=64] -->
+ <string name="copy_text">Copy to clipboard</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</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 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 calling a contact by shortcut -->
+ <string name="call_by_shortcut"><xliff:g id="contact_name">%s</xliff:g> (Call)</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</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 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 SMS to a contact by shortcut -->
+ <string name="sms_by_shortcut"><xliff:g id="contact_name">%s</xliff:g> (Message)</string>
+
+ <!-- Description string for an action button to initiate a video call. -->
+ <string name="description_video_call">Make video call</string>
+
+ <!-- Title of the confirmation dialog for clearing frequents. [CHAR LIMIT=37] -->
+ <string name="clearFrequentsConfirmation_title">Clear frequently contacted?</string>
+
+ <!-- Confirmation dialog for clearing frequents. [CHAR LIMIT=NONE] -->
+ <string name="clearFrequentsConfirmation">You\'ll clear the frequently contacted list in the
+ Contacts and Phone apps, and force email apps to learn your addressing preferences from
+ scratch.
+ </string>
+
+ <!-- Title of the "Clearing frequently contacted" progress-dialog [CHAR LIMIT=35] -->
+ <string name="clearFrequentsProgress_title">Clearing frequently contacted\u2026</string>
+
+ <!-- Used to display as default status when the contact is available for chat [CHAR LIMIT=19] -->
+ <string name="status_available">Available</string>
+
+ <!-- Used to display as default status when the contact is away or idle for chat [CHAR LIMIT=19] -->
+ <string name="status_away">Away</string>
+
+ <!-- Used to display as default status when the contact is busy or Do not disturb for chat [CHAR LIMIT=19] -->
+ <string name="status_busy">Busy</string>
+
+ <!-- Directory partition name (also exists in contacts) -->
+ <string name="contactsList">Contacts</string>
+
+ <!-- The name of the invisible local contact directory -->
+ <string name="local_invisible_directory">Other</string>
+
+ <!-- The label in section header in the contact list for a contact directory [CHAR LIMIT=128] -->
+ <string name="directory_search_label">Directory</string>
+
+ <!-- The label in section header in the contact list for a work contact directory [CHAR LIMIT=128] -->
+ <string name="directory_search_label_work">Work directory</string>
+
+ <!-- The label in section header in the contact list for a local contacts [CHAR LIMIT=128] -->
+ <string name="local_search_label">All contacts</string>
+
+ <!-- Title shown in the search result activity of contacts app while searching. [CHAR LIMIT=20]
+ (also in contacts) -->
+ <string name="search_results_searching">Searching\u2026</string>
+
+ <!-- Displayed at the top of search results indicating that more contacts were found than shown [CHAR LIMIT=64] -->
+ <string name="foundTooManyContacts">More than <xliff:g id="count">%d</xliff:g> found.</string>
+
+ <!-- Displayed at the top of the contacts showing the zero total number of contacts found when "Only contacts with phones" not selected. [CHAR LIMIT=30]
+ (also in contacts) -->
+ <string name="listFoundAllContactsZero">No contacts</string>
+
+ <!-- Displayed at the top of the contacts showing the total number of contacts found when typing search query -->
+ <plurals name="searchFoundContacts">
+ <item quantity="one">1 found</item>
+ <item quantity="other"><xliff:g id="count">%d</xliff:g> found</item>
+ </plurals>
+
+ <!-- String describing the text for photo of a contact in a contacts list.
+
+ Note: AccessibilityServices use this attribute to announce what the view represents.
+ This is especially valuable for views without textual representation like ImageView.
+ -->
+ <string name="description_quick_contact_for">Quick contact for <xliff:g id="name">%1$s</xliff:g></string>
+
+ <!-- Shown as the display name for a person when the name is missing or unknown. [CHAR LIMIT=18]-->
+ <string name="missing_name">(No name)</string>
+
+ <!-- The text displayed on the divider for the Favorites tab in People app indicating that items below it are frequently contacted [CHAR LIMIT = 39] -->
+ <string name="favoritesFrequentContacted">Frequently contacted</string>
+
+ <!-- String describing a contact picture that introduces users to the contact detail screen.
+
+ Used by AccessibilityService to announce the purpose of the button.
+
+ [CHAR LIMIT=NONE]
+ -->
+ <string name="description_view_contact_detail" msgid="2795575601596468581">View contact</string>
+
+ <!-- Contact list filter selection indicating that the list shows all contacts with phone numbers [CHAR LIMIT=64] -->
+ <string name="list_filter_phones">All contacts with phone numbers</string>
+
+ <!-- Contact list filter selection indicating that the list shows all work contacts with phone numbers [CHAR LIMIT=64] -->
+ <string name="list_filter_phones_work">Work profile contacts</string>
+
+ <!-- Button to view the updates from the current group on the group detail page [CHAR LIMIT=25] -->
+ <string name="view_updates_from_group">View updates</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. [CHAR LIMIT=20] -->
+ <string name="account_phone">Device</string>
+
+ <!-- Header that expands to list all name types when editing a structured name of a contact
+ [CHAR LIMIT=20] -->
+ <string name="nameLabelsGroup">Name</string>
+
+ <!-- Header that expands to list all nickname types when editing a nickname of a contact
+ [CHAR LIMIT=20] -->
+ <string name="nicknameLabelsGroup">Nickname</string>
+
+ <!-- Field title for the full name of a contact [CHAR LIMIT=64]-->
+ <string name="full_name">Name</string>
+ <!-- Field title for the given name of a contact -->
+ <string name="name_given">First name</string>
+ <!-- Field title for the family name of a contact -->
+ <string name="name_family">Last 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 name of a contact [CHAR LIMIT=64]-->
+ <string name="name_phonetic">Phonetic name</string>
+
+ <!-- Field title for the phonetic given name of a contact -->
+ <string name="name_phonetic_given">Phonetic first 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 last name</string>
+
+ <!-- Header that expands to list all of the types of phone numbers when editing or creating a
+ phone number for a contact [CHAR LIMIT=20] -->
+ <string name="phoneLabelsGroup">Phone</string>
+
+ <!-- Header that expands to list all of the types of email addresses when editing or creating
+ an email address for a contact [CHAR LIMIT=20] -->
+ <string name="emailLabelsGroup">Email</string>
+
+ <!-- Header that expands to list all of the types of postal addresses when editing or creating
+ an postal address for a contact [CHAR LIMIT=20] -->
+ <string name="postalLabelsGroup">Address</string>
+
+ <!-- Header that expands to list all of the types of IM account when editing or creating an IM
+ account for a contact [CHAR LIMIT=20] -->
+ <string name="imLabelsGroup">IM</string>
+
+ <!-- Header that expands to list all organization types when editing an organization of a
+ contact [CHAR LIMIT=20] -->
+ <string name="organizationLabelsGroup">Organization</string>
+
+ <!-- Header for the list of all relationships for a contact [CHAR LIMIT=20] -->
+ <string name="relationLabelsGroup">Relationship</string>
+
+ <!-- Header that expands to list all event types when editing an event of a contact
+ [CHAR LIMIT=20] -->
+ <string name="eventLabelsGroup">Special date</string>
+
+ <!-- Generic action string for text messaging a contact. Used by AccessibilityService to
+ announce the purpose of the view. [CHAR LIMIT=NONE] -->
+ <string name="sms">Text message</string>
+
+ <!-- Field title for the full postal address of a contact [CHAR LIMIT=64]-->
+ <string name="postal_address">Address</string>
+
+ <!-- Hint text for the organization name when editing -->
+ <string name="ghostData_company">Company</string>
+
+ <!-- Hint text for the organization title when editing -->
+ <string name="ghostData_title">Title</string>
+
+ <!-- The label describing the Notes field of a contact. This field allows free form text entry
+ about a contact -->
+ <string name="label_notes">Notes</string>
+
+ <!-- The label describing the SIP address field of a contact. [CHAR LIMIT=20] -->
+ <string name="label_sip_address">SIP</string>
+
+ <!-- Header that expands to list all website types when editing a website of a contact
+ [CHAR LIMIT=20] -->
+ <string name="websiteLabelsGroup">Website</string>
+
+ <!-- Header for the list of all labels for a contact [CHAR LIMIT=20] -->
+ <string name="groupsLabel">Labels</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</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>
+
+ <!-- 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>
+
+ <!-- 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 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>
+
+ <!-- String describing the Contact Editor Minus button
+
+ Used by AccessibilityService to announce the purpose of the button.
+
+ [CHAR LIMIT=NONE]
+ -->
+ <string name="description_minus_button">delete</string>
+
+ <!-- Content description for the expand or collapse name fields button.
+ Clicking this button causes the name editor to toggle between showing
+ a single field where the entire name is edited at once, or multiple
+ fields corresponding to each part of the name (Name Prefix, First Name,
+ Middle Name, Last Name, Name Suffix).
+ [CHAR LIMIT=NONE] -->
+ <string name="expand_collapse_name_fields_description">Expand or collapse name fields</string>
+
+ <!-- Content description for the expand or collapse phonetic name fields button. [CHAR LIMIT=100] -->
+ <string name="expand_collapse_phonetic_name_fields_description">Expand or collapse phonetic
+ name fields</string>
+
+ <!-- Contact list filter label indicating that the list is showing all available accounts [CHAR LIMIT=64] -->
+ <string name="list_filter_all_accounts">All contacts</string>
+
+ <!-- Contact list filter label indicating that the list is showing all starred contacts [CHAR LIMIT=64] -->
+ <string name="list_filter_all_starred">Starred</string>
+
+ <!-- Contact list filter selection indicating that the list shows groups chosen by the user [CHAR LIMIT=64] -->
+ <string name="list_filter_customize">Customize</string>
+
+ <!-- Contact list filter selection indicating that the list shows only the selected contact [CHAR LIMIT=64] -->
+ <string name="list_filter_single">Contact</string>
+
+ <!-- List title for a special contacts group that covers all contacts. [CHAR LIMIT=25] -->
+ <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. [CHAR LIMIT=25] -->
+ <string name="display_all_contacts">All contacts</string>
+
+ <!-- Menu item to remove a contacts sync group. [CHAR LIMIT=40] -->
+ <string name="menu_sync_remove">Remove sync group</string>
+
+ <!-- Menu item to add a contacts sync group. [CHAR LIMIT=40] -->
+ <string name="dialog_sync_add">Add sync group</string>
+
+ <!-- Text displayed in the sync groups footer view for unknown sync groups. [CHAR LIMIT=40 -->
+ <string name="display_more_groups">More groups\u2026</string>
+
+ <!-- Warning message given to users just before they remove a currently syncing
+ group that would also cause all ungrouped contacts to stop syncing. [CHAR LIMIT=NONE] -->
+ <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>
+
+ <!-- Displayed in a spinner dialog as user changes to display options are saved -->
+ <string name="savingDisplayGroups">Saving display options\u2026</string>
+
+ <!-- Menu item to indicate you are done editing a contact and want to save the changes you've made -->
+ <string name="menu_done">Done</string>
+
+ <!-- Menu item to indicate you want to cancel the current editing process and NOT save the changes you've made [CHAR LIMIT=12] -->
+ <string name="menu_doNotSave">Cancel</string>
+
+ <!-- Displayed at the top of the contacts showing single contact. [CHAR LIMIT=50] -->
+ <string name="listCustomView">Customized view</string>
+
+ <!-- Message asking user to select an account to save contacts imported from vcard or SIM card [CHAR LIMIT=64] -->
+ <string name="dialog_new_contact_account">Save imported contacts to:</string>
+
+ <!-- Action string for selecting SIM for importing contacts -->
+ <string name="import_from_sim">Import from SIM card</string>
+
+ <!-- Action string for selecting a SIM subscription for importing contacts -->
+ <string name="import_from_sim_summary">Import from SIM <xliff:g id="sim_name">^1</xliff:g> - <xliff:g id="sim_number">^2</xliff:g></string>
+
+ <!-- Action string for selecting a SIM subscription for importing contacts, without a phone number -->
+ <string name="import_from_sim_summary_no_number">Import from SIM <xliff:g id="sim_name">%1$s</xliff:g></string>
+
+ <!-- Action string for selecting a .vcf file to import contacts from [CHAR LIMIT=30] -->
+ <string name="import_from_vcf_file" product="default">Import from .vcf file</string>
+
+ <!-- Message shown in a Dialog confirming a user's cancel request toward existing vCard import.
+ The argument is file name for the vCard import the user wants to cancel.
+ [CHAR LIMIT=128] -->
+ <string name="cancel_import_confirmation_message">Cancel import of <xliff:g id="filename" example="import.vcf">%s</xliff:g>?</string>
+
+ <!-- Message shown in a Dialog confirming a user's cancel request toward existing vCard export.
+ The argument is file name for the vCard export the user wants to cancel.
+ [CHAR LIMIT=128] -->
+ <string name="cancel_export_confirmation_message">Cancel export of <xliff:g id="filename" example="export.vcf">%s</xliff:g>?</string>
+
+ <!-- Title shown in a Dialog telling users cancel vCard import/export operation is failed. [CHAR LIMIT=40] -->
+ <string name="cancel_vcard_import_or_export_failed">Couldn\'t cancel vCard import/export</string>
+
+ <!-- The failed reason which should not be shown but it may in some buggy condition. [CHAR LIMIT=40] -->
+ <string name="fail_reason_unknown">Unknown error.</string>
+
+ <!-- The failed reason shown when vCard importer/exporter could not open the file
+ specified by a user. The file name should be in the message. [CHAR LIMIT=NONE] -->
+ <string name="fail_reason_could_not_open_file">Couldn\'t open \"<xliff:g id="file_name">%s</xliff:g>\": <xliff:g id="exact_reason">%s</xliff:g>.</string>
+
+ <!-- The failed reason shown when contacts exporter fails to be initialized.
+ Some exact reason must follow this. [CHAR LIMIT=NONE]-->
+ <string name="fail_reason_could_not_initialize_exporter">Couldn\'t start the exporter: \"<xliff:g id="exact_reason">%s</xliff:g>\".</string>
+
+ <!-- The failed reason shown when there's no contact which is allowed to be exported.
+ Note that user may have contacts data but all of them are probably not allowed to be
+ exported because of security/permission reasons. [CHAR LIMIT=NONE] -->
+ <string name="fail_reason_no_exportable_contact">There is no exportable contact.</string>
+
+ <!-- The user doesn't have all permissions required to use the current screen. So
+ close the current screen and show the user this message. -->
+ <string name="missing_required_permission">You have disabled a required permission.</string>
+
+ <!-- The failed reason shown when some error happend during contacts export.
+ Some exact reason must follow this. [CHAR LIMIT=NONE] -->
+ <string name="fail_reason_error_occurred_during_export">An error occurred during export: \"<xliff:g id="exact_reason">%s</xliff:g>\".</string>
+
+ <!-- The failed reason shown when the given file name is too long for the system.
+ The length limit of each file is different in each Android device, so we don't need to
+ mention it here. [CHAR LIMIT=NONE] -->
+ <string name="fail_reason_too_long_filename">Required filename is too long (\"<xliff:g id="filename">%s</xliff:g>\").</string>
+
+ <!-- The failed reason shown when Contacts app (especially vCard importer/exporter)
+ emitted some I/O error. Exact reason will be appended by the system. [CHAR LIMIT=NONE] -->
+ <string name="fail_reason_io_error">I/O error</string>
+
+ <!-- Failure reason show when Contacts app (especially vCard importer) encountered
+ low memory problem and could not proceed its import procedure. [CHAR LIMIT=NONE] -->
+ <string name="fail_reason_low_memory_during_import">Not enough memory. The file may be too large.</string>
+
+ <!-- The failed reason shown when vCard parser was not able to be parsed by the current vCard
+ implementation. This might happen even when the input vCard is completely valid, though
+ we believe it is rather rare in the actual world. [CHAR LIMIT=NONE] -->
+ <string name="fail_reason_vcard_parse_error">Couldn\'t parse vCard for an unexpected reason.</string>
+
+ <!-- The failed reason shown when vCard importer doesn't support the format.
+ This may be shown when the vCard is corrupted [CHAR LIMIT=40] -->
+ <string name="fail_reason_not_supported">The format isn\'t supported.</string>
+
+ <!-- Fail reason shown when vCard importer failed to look over meta information stored in vCard file(s). -->
+ <string name="fail_reason_failed_to_collect_vcard_meta_info">Couldn\'t collect meta information of given vCard file(s).</string>
+
+ <!-- The failed reason shown when the import of some of vCard files failed during multiple vCard
+ files import. It includes the case where all files were failed to be imported. -->
+ <string name="fail_reason_failed_to_read_files">One or more files couldn\'t be imported (%s).</string>
+
+ <!-- The title shown when exporting vCard is successfuly finished [CHAR LIMIT=40] -->
+ <string name="exporting_vcard_finished_title">Finished exporting <xliff:g id="filename" example="export.vcf">%s</xliff:g>.</string>
+
+ <!-- The title shown when exporting vCard has finished successfully but the destination filename could not be resolved. [CHAR LIMIT=NONE] -->
+ <string name="exporting_vcard_finished_title_fallback">Finished exporting contacts.</string>
+
+ <!-- The toast message shown when exporting vCard has finished and vCards are ready to be shared [CHAR LIMIT=150]-->
+ <string name="exporting_vcard_finished_toast">Finished exporting contacts, click the notification to share contacts.</string>
+
+ <!-- The message on notification shown when exporting vCard has finished and vCards are ready to be shared [CHAR LIMIT=60]-->
+ <string name="touch_to_share_contacts">Tap to share contacts.</string>
+
+ <!-- The title shown when exporting vCard is canceled (probably by a user)
+ The argument is file name the user canceled importing.
+ [CHAR LIMIT=40] -->
+ <string name="exporting_vcard_canceled_title">Exporting <xliff:g id="filename" example="export.vcf">%s</xliff:g> canceled.</string>
+
+ <!-- Dialog title shown when the application is exporting contact data outside. [CHAR LIMIT=NONE] -->
+ <string name="exporting_contact_list_title">Exporting contact data</string>
+
+ <!-- Message shown when the application is exporting contact data outside -->
+ <string name="exporting_contact_list_message">Contact data is being exported.</string>
+
+ <!-- The error reason the vCard composer "may" emit when database is corrupted or
+ something is going wrong. Usually users should not see this text. [CHAR LIMIT=NONE] -->
+ <string name="composer_failed_to_get_database_infomation">Couldn\'t get database information.</string>
+
+ <!-- This error message shown when the user actually have no contact
+ (e.g. just after data-wiping), or, data providers of the contact list prohibits their
+ contacts from being exported to outside world via vcard exporter, etc. [CHAR LIMIT=NONE] -->
+ <string name="composer_has_no_exportable_contact">There are no exportable contacts. If you do have contacts on your phone, some data providers may not allow the contacts to be exported from the phone.</string>
+
+ <!-- The error reason the vCard composer may emit when vCard composer is not initialized
+ even when needed.
+ Users should not usually see this error message. [CHAR LIMIT=NONE] -->
+ <string name="composer_not_initialized">The vCard composer didn\'t start properly.</string>
+
+ <!-- Dialog title shown when exporting Contact data failed. [CHAR LIMIT=20] -->
+ <string name="exporting_contact_failed_title">Couldn\'t export</string>
+
+ <!-- Dialog message shown when exporting Contact data failed. [CHAR LIMIT=NONE] -->
+ <string name="exporting_contact_failed_message">The contact data wasn\'t exported.\nReason: \"<xliff:g id="fail_reason">%s</xliff:g>\"</string>
+
+ <!-- Description shown when importing vCard data.
+ The argument is the name of a contact which is being read.
+ [CHAR LIMIT=20] -->
+ <string name="importing_vcard_description">Importing <xliff:g id="name" example="Joe Due">%s</xliff:g></string>
+
+ <!-- Dialog title shown when reading vCard data failed [CHAR LIMIT=40] -->
+ <string name="reading_vcard_failed_title">Couldn\'t read vCard data</string>
+
+ <!-- The title shown when reading vCard is canceled (probably by a user)
+ [CHAR LIMIT=40] -->
+ <string name="reading_vcard_canceled_title">Reading vCard data canceled</string>
+
+ <!-- The title shown when reading vCard finished
+ The argument is file name the user imported.
+ [CHAR LIMIT=40] -->
+ <string name="importing_vcard_finished_title">Finished importing vCard <xliff:g id="filename" example="import.vcf">%s</xliff:g></string>
+
+ <!-- The title shown when importing vCard is canceled (probably by a user)
+ The argument is file name the user canceled importing.
+ [CHAR LIMIT=40] -->
+ <string name="importing_vcard_canceled_title">Importing <xliff:g id="filename" example="import.vcf">%s</xliff:g> canceled</string>
+
+ <!-- The message shown when vCard import request is accepted. The system may start that work soon, or do it later
+ when there are already other import/export requests.
+ The argument is file name the user imported.
+ [CHAR LIMIT=40] -->
+ <string name="vcard_import_will_start_message"><xliff:g id="filename" example="import.vcf">%s</xliff:g> will be imported shortly.</string>
+ <!-- The message shown when vCard import request is accepted. The system may start that work soon, or do it later when there are already other import/export requests.
+ "The file" is what a user selected for importing.
+ [CHAR LIMIT=40] -->
+ <string name="vcard_import_will_start_message_with_default_name">The file will be imported shortly.</string>
+ <!-- The message shown when a given vCard import request is rejected by the system. [CHAR LIMIT=NONE] -->
+ <string name="vcard_import_request_rejected_message">vCard import request was rejected. Try again later.</string>
+ <!-- The message shown when vCard export request is accepted. The system may start that work soon, or do it later
+ when there are already other import/export requests.
+ The argument is file name the user exported.
+ [CHAR LIMIT=40] -->
+ <string name="vcard_export_will_start_message"><xliff:g id="filename" example="import.vcf">%s</xliff:g> will be exported shortly.</string>
+
+ <!-- The message shown when a vCard export request is accepted but the destination filename could not be resolved. [CHAR LIMIT=NONE] -->
+ <string name="vcard_export_will_start_message_fallback">The file will be exported shortly.</string>
+
+ <!-- The message shown when a vCard export request is accepted and contacts will be exported shortly. [CHAR LIMIT=70]-->
+ <string name="contacts_export_will_start_message">Contacts will be exported shortly.</string>
+
+ <!-- The message shown when a given vCard export request is rejected by the system. [CHAR LIMIT=NONE] -->
+ <string name="vcard_export_request_rejected_message">vCard export request was rejected. Try again later.</string>
+ <!-- Used when file name is unknown in vCard processing. It typically happens
+ when the file is given outside the Contacts app. [CHAR LIMIT=30] -->
+ <string name="vcard_unknown_filename">contact</string>
+
+ <!-- The message shown when vCard importer is caching files to be imported into local temporary
+ data storage. [CHAR LIMIT=NONE] -->
+ <string name="caching_vcard_message">Caching vCard(s) to local temporary storage. The actual import will start soon.</string>
+
+ <!-- Message used when vCard import has failed. [CHAR LIMIT=40] -->
+ <string name="vcard_import_failed">Couldn\'t import vCard.</string>
+
+ <!-- The "file name" displayed for vCards received directly via NFC [CHAR LIMIT=16] -->
+ <string name="nfc_vcard_file_name">Contact received over NFC</string>
+
+ <!-- Dialog title shown when a user confirms whether he/she export Contact data. [CHAR LIMIT=32] -->
+ <string name="confirm_export_title">Export contacts?</string>
+
+ <!-- The title shown when vCard importer is caching files to be imported into local temporary
+ data storage. [CHAR LIMIT=40] -->
+ <string name="caching_vcard_title">Caching</string>
+
+ <!-- The message shown while importing vCard(s).
+ First argument is current index of contacts to be imported.
+ Second argument is the total number of contacts.
+ Third argument is the name of a contact which is being read.
+ [CHAR LIMIT=20] -->
+ <string name="progress_notifier_message">Importing <xliff:g id="current_number">%s</xliff:g>/<xliff:g id="total_number">%s</xliff:g>: <xliff:g id="name" example="Joe Due">%s</xliff:g></string>
+
+ <!-- Action that exports all contacts to a user selected destination. [CHAR LIMIT=25] -->
+ <string name="export_to_vcf_file" product="default">Export to .vcf file</string>
+
+ <!-- Contact preferences related strings -->
+
+ <!-- Label of the "sort by" display option -->
+ <string name="display_options_sort_list_by">Sort by</string>
+
+ <!-- An allowable value for the "sort list by" contact display option -->
+ <string name="display_options_sort_by_given_name">First name</string>
+
+ <!-- An allowable value for the "sort list by" contact display option -->
+ <string name="display_options_sort_by_family_name">Last name</string>
+
+ <!-- Label of the "name format" display option [CHAR LIMIT=64]-->
+ <string name="display_options_view_names_as">Name format</string>
+
+ <!-- An allowable value for the "view names as" contact display option -->
+ <string name="display_options_view_given_name_first">First name first</string>
+
+ <!-- An allowable value for the "view names as" contact display option -->
+ <string name="display_options_view_family_name_first">Last name first</string>
+
+ <!--Lable of the "Accounts" in settings [CHAR LIMIT=30]-->
+ <string name="settings_accounts">Accounts</string>
+
+ <!--Label of the "default account" setting option to set default editor account. [CHAR LIMIT=80]-->
+ <string name="default_editor_account">Default account for new contacts</string>
+
+ <!--Label of the "Sync contact metadata" setting option to set sync account for Lychee. [CHAR LIMIT=80]-->
+ <string name="sync_contact_metadata_title">Sync contact metadata [DOGFOOD]</string>
+
+ <!--Label of the "Sync contact metadata" setting dialog to set sync account for Lychee. [CHAR LIMIT=80]-->
+ <string name="sync_contact_metadata_dialog_title">Sync contact metadata</string>
+
+ <!-- Title of my info preference, showing the name of user's personal profile [CHAR LIMIT=30]-->
+ <string name="settings_my_info_title">My info</string>
+
+ <!-- Displayed below my info for user to set up the user's personal profile entry [CHAR LIMIT=64] -->
+ <string name="set_up_profile">Set up your profile</string>
+
+ <!-- Label of the "About" setting -->
+ <string name="setting_about">About Contacts</string>
+
+ <!-- Title of the settings activity [CHAR LIMIT=64] -->
+ <string name="activity_title_settings">Settings</string>
+
+ <!-- Action that shares visible contacts -->
+ <string name="share_visible_contacts">Share visible contacts</string>
+
+ <!-- A framework exception (ie, transaction too large) can be thrown while attempting to share all visible contacts. If so, show this toast. -->
+ <string name="share_visible_contacts_failure">Failed to share visible contacts.</string>
+
+ <!-- Action that shares favorite contacts [CHAR LIMIT=40]-->
+ <string name="share_favorite_contacts">Share favorite contacts</string>
+
+ <!-- Action that shares contacts [CHAR LIMIT=30]-->
+ <string name="share_contacts">Share all contacts</string>
+
+ <!-- A framework exception can be thrown while attempting to share all contacts. If so, show this toast. [CHAR LIMIT=40]-->
+ <string name="share_contacts_failure">Failed to share contacts.</string>
+
+ <!-- Dialog title when selecting the bulk operation to perform from a list. [CHAR LIMIT=36] -->
+ <string name="dialog_import_export">Import/export contacts</string>
+
+ <!-- Dialog title when importing contacts from an external source. [CHAR LIMIT=36] -->
+ <string name="dialog_import">Import contacts</string>
+
+ <!-- Toast indicating that sharing a contact has failed. [CHAR LIMIT=NONE] -->
+ <string name="share_error">This contact can\'t be shared.</string>
+
+ <!-- Toast indicating that no visible contact to share [CHAR LIMIT=NONE] -->
+ <string name="no_contact_to_share">There are no contacts to share.</string>
+
+ <!-- Menu item to search contacts -->
+ <string name="menu_search">Search</string>
+
+ <!-- The menu item to filter the list of contacts displayed -->
+ <string name="menu_contacts_filter">Contacts to display</string>
+
+ <!-- Title of the activity that allows the uesr to filter the list of contacts displayed according to account [CHAR LIMIT=25] -->
+ <string name="activity_title_contacts_filter">Contacts to display</string>
+
+ <!-- Title of the activity that allows the user to customize filtering of contact list [CHAR LIMIT=128] -->
+ <string name="custom_list_filter">Define customized view</string>
+
+ <!-- Menu item to save changes to custom filter. [CHAR LIMIT=15] -->
+ <string name="menu_custom_filter_save">Save</string>
+
+ <!-- Query hint displayed inside the search field [CHAR LIMIT=64] -->
+ <string name="hint_findContacts">Search contacts</string>
+
+ <!-- The description text for the favorites tab.
+
+ Note: AccessibilityServices use this attribute to announce what the view represents.
+ This is especially valuable for views without textual representation like ImageView.
+
+ [CHAR LIMIT=NONE] -->
+ <string name="contactsFavoritesLabel">Favorites</string>
+
+ <!-- Displayed at the top of the contacts showing the zero total number of contacts visible when "All contacts" is selected [CHAR LIMIT=64]-->
+ <string name="listTotalAllContactsZero">No contacts.</string>
+
+ <!-- The menu item to clear frequents [CHAR LIMIT=30] -->
+ <string name="menu_clear_frequents">Clear frequents</string>
+
+ <!-- Menu item to select SIM card -->
+ <string name="menu_select_sim">Select SIM card</string>
+
+ <!-- The menu item to open the list of accounts. [CHAR LIMIT=60]-->
+ <string name="menu_accounts">Manage accounts</string>
+
+ <!-- The menu item to bulk import or bulk export contacts from SIM card or SD card. [CHAR LIMIT=30]-->
+ <string name="menu_import_export">Import/export</string>
+
+ <!-- The menu item to open blocked numbers activity [CHAR LIMIT=60]-->
+ <string name="menu_blocked_numbers">Blocked numbers</string>
+
+ <!-- The font-family to use for tab text.
+ Do not translate. -->
+ <string name="tab_font_family">sans-serif</string>
+
+ <!-- Attribution of a contact status update, when the time of update is unknown -->
+ <string name="contact_status_update_attribution">via <xliff:g id="source" example="Google Talk">%1$s</xliff:g></string>
+
+ <!-- Attribution of a contact status update, when the time of update is known -->
+ <string name="contact_status_update_attribution_with_date"><xliff:g id="date" example="3 hours ago">%1$s</xliff:g> via <xliff:g id="source" example="Google Talk">%2$s</xliff:g></string>
+
+ <!-- Font family used when drawing letters for letter tile avatars.
+ Do not translate. -->
+ <string name="letter_tile_letter_font_family">sans-serif-medium</string>
+
+ <!-- Content description for the fake action menu up button as used
+ inside search. [CHAR LIMIT=NONE] -->
+ <string name="action_menu_back_from_search">stop searching</string>
+
+ <!-- String describing the icon used to clear the search field -->
+ <string name="description_clear_search">Clear search</string>
+
+ <!-- The font-family to use for the text inside the searchbox.
+ Do not translate. -->
+ <string name="search_font_family">sans-serif</string>
+
+ <!-- The title of the preference section that allows users to configure how they want their
+ contacts to be displayed. [CHAR LIMIT=128] -->
+ <string name="settings_contact_display_options_title">Contact display options</string>
+
+ <!-- Title for Select Account Dialog [CHAR LIMIT=30] -->
+ <string name="select_account_dialog_title">Account</string>
+
+ <!-- Label for the check box to toggle default sim card setting [CHAR LIMIT=35]-->
+ <string name="set_default_account">Always use this for calls</string>
+
+ <!-- Title for dialog to select Phone Account for outgoing call. [CHAR LIMIT=40] -->
+ <string name="select_phone_account_for_calls">Call with</string>
+
+ <!-- String used for actions in the dialer call log and the quick contact card to initiate
+ a call to an individual. The user is prompted to enter a note which is sent along with
+ the call (e.g. a call subject). [CHAR LIMIT=40] -->
+ <string name="call_with_a_note">Call with a note</string>
+
+ <!-- Hint text shown in the call subject dialog. [CHAR LIMIT=255] -->
+ <string name="call_subject_hint">Type a note to send with call ...</string>
+
+ <!-- Button used to start a new call with the user entered subject. [CHAR LIMIT=32] -->
+ <string name="send_and_call_button">SEND & CALL</string>
+
+ <!-- String used to represent the total number of characters entered for a call subject,
+ compared to the character limit. Example: 2 / 64 -->
+ <string name="call_subject_limit"><xliff:g id="count" example="4">%1$s</xliff:g> / <xliff:g id="limit" example="64">%2$s</xliff:g></string>
+
+ <!-- String used to build a phone number bype and phone number string.
+ Example: Mobile • 650-555-1212 -->
+ <string name="call_subject_type_and_number"><xliff:g id="type" example="Mobile">%1$s</xliff:g> • <xliff:g id="number" example="(650) 555-1212">%2$s</xliff:g></string>
+
+ <!-- String format to describe the number of unread items in a tab.
+
+ Note: AccessibilityServices use this attribute to announce what the view represents.
+ This is especially valuable for views without textual representation like ImageView.
+ -->
+ <plurals name="tab_title_with_unread_items">
+ <item quantity="one">
+ <xliff:g id="title">%1$s</xliff:g>. <xliff:g id="count">%2$d</xliff:g> unread item.
+ </item>
+ <item quantity="other">
+ <xliff:g id="title">%1$s</xliff:g>. <xliff:g id="count">%2$d</xliff:g> unread items.
+ </item>
+ </plurals>
+
+ <!-- Build version title in About preference. [CHAR LIMIT=40]-->
+ <string name="about_build_version">Build version</string>
+
+ <!-- Open source licenses title in About preference. [CHAR LIMIT=60] -->
+ <string name="about_open_source_licenses">Open source licenses</string>
+
+ <!-- Open source licenses summary in About preference. [CHAR LIMIT=NONE] -->
+ <string name="about_open_source_licenses_summary">License details for open source software</string>
+
+ <!-- Privacy policy title in About preference. [CHAR LIMIT=40]-->
+ <string name="about_privacy_policy">Privacy policy</string>
+
+ <!-- Terms of service title in about preference. [CHAR LIMIT=60]-->
+ <string name="about_terms_of_service">Terms of service</string>
+
+ <!-- Title for the activity that displays licenses for open source libraries. [CHAR LIMIT=100]-->
+ <string name="activity_title_licenses">Open source licenses</string>
+
+ <!-- Toast message showing when failed to open the url. [CHAR LIMIT=100]-->
+ <string name="url_open_error_toast">Failed to open the url.</string>
+
+ <!-- Content description of entries (including that radio button is checked) in contact
+ accounts list filter. For example: Google abc@gmail.com checked, etc [CHAR LIMIT=30]-->
+ <string name="account_filter_view_checked"><xliff:g id="account_info">%s</xliff:g> checked</string>
+
+ <!-- Content description of entries (including that the radio button is not checked) in contact
+ accounts list filter. For example: Google abc@gmail.com not checked, etc [CHAR LIMIT=30]-->
+ <string name="account_filter_view_not_checked"><xliff:g id="account_info">%s</xliff:g> not checked</string>
+
+ <!-- Description string for an action button to initiate a video call from search results.
+ Note: AccessibilityServices use this attribute to announce what the view represents.
+ This is especially valuable for views without textual representation like ImageView.
+
+ [CHAR LIMIT=NONE]-->
+ <string name="description_search_video_call">Place video call</string>
+
+ <!-- Content description of delete contact button [CHAR LIMIT=30]-->
+ <string name="description_delete_contact">Delete</string>
+
+ <!-- Content description for (...) in no name header [CHAR LIMIT=30]-->
+ <string name="description_no_name_header">Ellipsis</string>
+
+ <!-- Formatted call duration displayed in recent card in QuickContact, for duration less than 1 minute -->
+ <string name="callDurationSecondFormat"><xliff:g id="seconds">%s</xliff:g> sec</string>
+
+ <!-- Formatted call duration displayed in recent card in QuickContact, for duration less than 1 hour -->
+ <string name="callDurationMinuteFormat"><xliff:g id="minutes">%s</xliff:g> min <xliff:g id="seconds">%s</xliff:g> sec</string>
+
+ <!-- Formatted call duration displayed in recent card in QuickContact, for duration more than 1 hour -->
+ <string name="callDurationHourFormat"><xliff:g id="minutes">%s</xliff:g> hr <xliff:g id="minutes">%s</xliff:g> min <xliff:g id="seconds">%s</xliff:g> sec</string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 9c6ace4..9ff882d 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -434,4 +434,98 @@
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textAllCaps">true</item>
</style>
+ <style name="DirectoryHeader">
+ <item name="android:background">@android:color/transparent</item>
+ </style>
+
+ <style name="SectionHeaderStyle" parent="@android:style/TextAppearance.Large">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textAllCaps">true</item>
+ <item name="android:textColor">@color/section_header_text_color</item>
+ <item name="android:textStyle">bold</item>
+ </style>
+
+ <style name="DirectoryHeaderStyle" parent="@android:style/TextAppearance.Small">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@color/dialtacts_secondary_text_color</item>
+ <item name="android:fontFamily">sans-serif-medium</item>
+ </style>
+
+ <!-- TextView style used for headers.
+
+This is similar to ?android:attr/listSeparatorTextView but uses different
+background and text color. See also android:style/Widget.Holo.TextView.ListSeparator
+(which is private, so we cannot specify it as a parent style). -->
+ <style name="ContactListSeparatorTextViewStyle">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <!-- See comments for @dimen/list_section_divider_min_height -->
+ <item name="android:minHeight">@dimen/list_section_divider_min_height</item>
+ <item name="android:textAppearance">@style/DirectoryHeaderStyle</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:paddingLeft">8dip</item>
+ <item name="android:paddingStart">8dip</item>
+ <item name="android:paddingTop">4dip</item>
+ <item name="android:paddingBottom">4dip</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:textAllCaps">true</item>
+ </style>
+
+ <style name="TextAppearanceMedium" parent="@android:style/TextAppearance.Medium">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">#000000</item>
+ </style>
+
+ <style name="TextAppearanceSmall" parent="@android:style/TextAppearance.Small">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">#737373</item>
+ </style>
+
+ <style name="ListViewStyle" parent="@android:style/Widget.Material.Light.ListView">
+ <item name="android:overScrollMode">always</item>
+ </style>
+
+ <style name="ContactListFilterTheme" parent="@android:Theme.Holo.Light">
+ <item name="android:listViewStyle">@style/ListViewStyle</item>
+ <item name="android:actionButtonStyle">@style/FilterActionButtonStyle</item>
+ </style>
+
+ <!-- Adding padding to action button doesn't move it to left, we increase the button width to
+ make margin between the button and screen edge 16dp -->
+ <style name="FilterActionButtonStyle" parent="@android:Widget.ActionButton">
+ <item name="android:minWidth">@dimen/contact_filter_action_button_width</item>
+ <item name="android:textColor">@color/actionbar_text_color</item>
+ </style>
+
+ <style name="CustomContactListFilterView" parent="ContactListFilterTheme">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">match_parent</item>
+ </style>
+
+ <style name="BackgroundOnlyTheme" parent="@android:style/Theme.Material.Light">
+ <item name="android:windowBackground">@null</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowAnimationStyle">@null</item>
+ <item name="android:windowNoTitle">true</item>
+ <!-- Activities that use this theme are background activities without obvious displays.
+ However, some also have dialogs. Therefore, it doesn't make sense to set this true.-->
+ <item name="android:windowNoDisplay">false</item>
+ <item name="android:windowIsFloating">true</item>
+ </style>
+
+ <style name="Theme.CallSubjectDialogTheme" parent="@android:style/Theme.Material.Light.Dialog">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">match_parent</item>
+
+ <!-- No backgrounds, titles or window float -->
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowFullscreen">false</item>
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowDrawsSystemBarBackgrounds">false</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowElevation">0dp</item>
+ </style>
</resources>
diff --git a/res/xml/preference_about.xml b/res/xml/preference_about.xml
new file mode 100644
index 0000000..a109db6
--- /dev/null
+++ b/res/xml/preference_about.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ <Preference
+ android:icon="@null"
+ android:key="@string/pref_build_version_key"
+ android:title="@string/about_build_version"/>
+
+ <Preference
+ android:icon="@null"
+ android:key="@string/pref_open_source_licenses_key"
+ android:title="@string/about_open_source_licenses"
+ android:summary="@string/about_open_source_licenses_summary"/>
+
+ <Preference
+ android:icon="@null"
+ android:key="@string/pref_privacy_policy_key"
+ android:title="@string/about_privacy_policy">
+ </Preference>
+
+ <Preference
+ android:icon="@null"
+ android:key="@string/pref_terms_of_service_key"
+ android:title="@string/about_terms_of_service">
+ </Preference>
+</PreferenceScreen>
diff --git a/res/xml/preference_display_options.xml b/res/xml/preference_display_options.xml
new file mode 100644
index 0000000..f7a6514
--- /dev/null
+++ b/res/xml/preference_display_options.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ <Preference
+ android:icon="@null"
+ android:key="myInfo"
+ android:title="@string/settings_my_info_title"/>
+
+ <Preference
+ android:icon="@null"
+ android:key="accounts"
+ android:title="@string/settings_accounts">
+ </Preference>
+
+ <com.android.contacts.common.preference.DefaultAccountPreference
+ android:icon="@null"
+ android:key="defaultAccount"
+ android:title="@string/default_editor_account"
+ android:dialogTitle="@string/default_editor_account" />
+
+ <Preference
+ android:icon="@null"
+ android:key="customContactsFilter"
+ android:title="@string/menu_contacts_filter"/>
+
+ <com.android.contacts.common.preference.SortOrderPreference
+ android:icon="@null"
+ android:key="sortOrder"
+ android:title="@string/display_options_sort_list_by"
+ android:dialogTitle="@string/display_options_sort_list_by" />
+
+ <com.android.contacts.common.preference.DisplayOrderPreference
+ android:icon="@null"
+ android:key="displayOrder"
+ android:title="@string/display_options_view_names_as"
+ android:dialogTitle="@string/display_options_view_names_as" />
+
+ <Preference
+ android:icon="@null"
+ android:key="importExport"
+ android:title="@string/menu_import_export"/>
+
+ <Preference
+ android:icon="@null"
+ android:key="blockedNumbers"
+ android:title="@string/menu_blocked_numbers" />
+
+ <Preference
+ android:icon="@null"
+ android:key="about"
+ android:title="@string/setting_about"
+ android:order="@integer/about_contacts_order_number"/>
+</PreferenceScreen>
diff --git a/src/com/android/contactsbind/Assistants.java b/src-bind/com/android/contactsbind/Assistants.java
similarity index 100%
rename from src/com/android/contactsbind/Assistants.java
rename to src-bind/com/android/contactsbind/Assistants.java
diff --git a/src/com/android/contactsbind/HelpUtils.java b/src-bind/com/android/contactsbind/HelpUtils.java
similarity index 100%
rename from src/com/android/contactsbind/HelpUtils.java
rename to src-bind/com/android/contactsbind/HelpUtils.java
diff --git a/src-bind/com/android/contactsbind/ObjectFactory.java b/src-bind/com/android/contactsbind/ObjectFactory.java
new file mode 100644
index 0000000..1a5b346
--- /dev/null
+++ b/src-bind/com/android/contactsbind/ObjectFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.contactsbind;
+
+import com.android.contacts.common.logging.Logger;
+import com.android.contacts.common.preference.PreferenceManager;
+
+import android.content.Context;
+
+/**
+ * Creates default bindings for overlays.
+ */
+public class ObjectFactory {
+
+ public static Logger getLogger() {
+ return null;
+ }
+
+ public static PreferenceManager getPreferenceManager(Context context) { return null; }
+}
diff --git a/src-bind/com/android/contactsbind/analytics/AnalyticsUtil.java b/src-bind/com/android/contactsbind/analytics/AnalyticsUtil.java
new file mode 100644
index 0000000..e48e8f2
--- /dev/null
+++ b/src-bind/com/android/contactsbind/analytics/AnalyticsUtil.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 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.contactsbind.analytics;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Fragment;
+import android.text.TextUtils;
+
+public class AnalyticsUtil {
+
+ /**
+ * Initialize this class and setup automatic activity tracking.
+ */
+ public static void initialize(Application application) { }
+
+ /**
+ * Log a screen view for {@param fragment}.
+ */
+ public static void sendScreenView(Fragment fragment) {}
+
+ public static void sendScreenView(Fragment fragment, Activity activity) {}
+
+ public static void sendScreenView(Fragment fragment, Activity activity, String tag) {}
+
+ public static void sendScreenView(String fragmentName, Activity activity, String tag) {}
+
+ /**
+ * Logs a event to the analytics server.
+ *
+ * @param application The application the tracker is stored in.
+ * @param category The category for the event.
+ * @param action The event action.
+ * @param label The event label.
+ * @param value The value associated with the event.
+ */
+ public static void sendEvent(Application application, String category, String action,
+ String label, long value) { }
+}
\ No newline at end of file
diff --git a/src-bind/com/android/contactsbind/experiments/Flags.java b/src-bind/com/android/contactsbind/experiments/Flags.java
new file mode 100644
index 0000000..5bf47e8
--- /dev/null
+++ b/src-bind/com/android/contactsbind/experiments/Flags.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 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.contactsbind.experiments;
+
+import android.content.Context;
+
+import com.android.contacts.common.Experiments;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Provides getters for experiment flags.
+ * This stub class is designed to be overwritten by an overlay.
+ */
+public final class Flags {
+
+ private static Flags sInstance;
+
+ private Map<String,Boolean> mMap;
+
+ public static Flags getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new Flags();
+ }
+ return sInstance;
+ }
+
+ private Flags() {
+ mMap = new HashMap<>();
+ }
+
+ public boolean getBoolean(String flagName) {
+ return mMap.containsKey(flagName) ? mMap.get(flagName) : false;
+ }
+}
diff --git a/src-bind/com/android/contactsbind/util/UserAgentGenerator.java b/src-bind/com/android/contactsbind/util/UserAgentGenerator.java
new file mode 100644
index 0000000..1cb44b8
--- /dev/null
+++ b/src-bind/com/android/contactsbind/util/UserAgentGenerator.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 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.contactsbind.util;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+/**
+ * Generates a user agent string for the application.
+ */
+public class UserAgentGenerator {
+ /**
+ * Builds a user agent string for the current application. No default implementation.
+ *
+ * @param context The context.
+ * @return The user agent string.
+ */
+ public static String getUserAgent(Context context) {
+ return null;
+ }
+}
diff --git a/src/com/android/contacts/ContactsApplication.java b/src/com/android/contacts/ContactsApplication.java
index 0ba1f02..f8a1f20 100644
--- a/src/com/android/contacts/ContactsApplication.java
+++ b/src/com/android/contacts/ContactsApplication.java
@@ -31,7 +31,7 @@
import com.android.contacts.common.testing.InjectedServices;
import com.android.contacts.common.util.Constants;
-import com.android.contacts.commonbind.analytics.AnalyticsUtil;
+import com.android.contactsbind.analytics.AnalyticsUtil;
import com.android.contacts.common.testing.NeededForTesting;
import com.google.common.annotations.VisibleForTesting;
diff --git a/src/com/android/contacts/ContactsDrawerActivity.java b/src/com/android/contacts/ContactsDrawerActivity.java
index c8d8eb3..bea1411 100644
--- a/src/com/android/contacts/ContactsDrawerActivity.java
+++ b/src/com/android/contacts/ContactsDrawerActivity.java
@@ -88,8 +88,7 @@
AccountFiltersListener,
GroupsListener,
NavigationView.OnNavigationItemSelectedListener,
- SelectAccountDialogFragment.Listener,
- GroupNameEditDialogFragment.Listener {
+ SelectAccountDialogFragment.Listener {
protected static String TAG = "ContactsDrawerActivity";
@@ -650,26 +649,11 @@
@Override
public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
mNewGroupAccount = account;
- GroupNameEditDialogFragment.showInsertDialog(
- getFragmentManager(), TAG_GROUP_NAME_EDIT_DIALOG);
+ GroupNameEditDialogFragment.newInstanceForCreation(mNewGroupAccount, ACTION_CREATE_GROUP)
+ .show(getFragmentManager(), TAG_GROUP_NAME_EDIT_DIALOG);
}
@Override
public void onAccountSelectorCancelled() {
}
-
- @Override
- public void onGroupNameEdit(String groupName, boolean isInsert) {
- if (mNewGroupAccount == null) {
- Toast.makeText(this, R.string.groupCreateFailedToast, Toast.LENGTH_SHORT).show();
- return;
- }
- startService(ContactSaveService.createNewGroupIntent(this,
- mNewGroupAccount, groupName, /* rawContactsToAdd */ null, getClass(),
- ACTION_CREATE_GROUP));
- }
-
- @Override
- public void onGroupNameEditCancelled() {
- }
}
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index eaf027d..b896406 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -16,6 +16,7 @@
package com.android.contacts.activities;
+import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
@@ -35,6 +36,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.Window;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -122,6 +124,8 @@
private FeatureHighlight mHamburgerFeatureHighlight;
+ private ValueAnimator mStatusBarAnimator;
+
public interface TabState {
public static int ALL = 0;
@@ -451,8 +455,6 @@
}
private void update(boolean skipAnimation) {
- updateStatusBarColor();
-
updateOverflowButtonColor();
final boolean isSelectionModeChanging
@@ -463,6 +465,8 @@
= (mSearchContainer.getParent() == null) == mSearchMode;
final boolean isTabHeightChanging = isSearchModeChanging || isSelectionModeChanging;
+ updateStatusBarColor(isSelectionModeChanging && !isSearchModeChanging);
+
// When skipAnimation=true, it is possible that we will switch from search mode
// to selection mode directly. So we need to remove the undesired container in addition
// to adding the desired container.
@@ -594,18 +598,46 @@
textView.setText(title);
}
- private void updateStatusBarColor() {
+ private void updateStatusBarColor(boolean shouldAnimate) {
if (!CompatUtils.isLollipopCompatible()) {
return; // we can't change the status bar color prior to Lollipop
}
+
if (mSelectionMode) {
- final int cabStatusBarColor = mActivity.getResources().getColor(
- R.color.contextual_selection_bar_status_bar_color);
- mActivity.getWindow().setStatusBarColor(cabStatusBarColor);
+ final int cabStatusBarColor = ContextCompat.getColor(
+ mActivity, R.color.contextual_selection_bar_status_bar_color);
+ runStatusBarAnimation(/* colorTo */ cabStatusBarColor);
} else {
final int normalStatusBarColor = ContextCompat.getColor(
mActivity, R.color.primary_color_dark);
- mActivity.getWindow().setStatusBarColor(normalStatusBarColor);
+ if (shouldAnimate) {
+ runStatusBarAnimation(/* colorTo */ normalStatusBarColor);
+ } else {
+ mActivity.getWindow().setStatusBarColor(normalStatusBarColor);
+ }
+ }
+ }
+
+ private void runStatusBarAnimation(int colorTo) {
+ final Window window = mActivity.getWindow();
+ if (window.getStatusBarColor() != colorTo) {
+ // Cancel running animation.
+ if (mStatusBarAnimator != null && mStatusBarAnimator.isRunning()) {
+ mStatusBarAnimator.cancel();
+ }
+ final int from = window.getStatusBarColor();
+ // Set up mStatusBarAnimator and run animation.
+ mStatusBarAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), from, colorTo);
+ mStatusBarAnimator.addUpdateListener(
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animator) {
+ window.setStatusBarColor((Integer) animator.getAnimatedValue());
+ }
+ });
+ mStatusBarAnimator.setDuration(mActionBarAnimationDuration);
+ mStatusBarAnimator.setStartDelay(0);
+ mStatusBarAnimator.start();
}
}
diff --git a/src/com/android/contacts/activities/ContactEditorBaseActivity.java b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
index 97095f0..c4abd58 100644
--- a/src/com/android/contacts/activities/ContactEditorBaseActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
@@ -231,6 +231,7 @@
actionBar.setTitle(getResources().getString(mActionBarTitleResId));
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeAsUpIndicator(R.drawable.ic_close_dk);
}
}
diff --git a/src/com/android/contacts/activities/GroupMembersActivity.java b/src/com/android/contacts/activities/GroupMembersActivity.java
index 093c8b6..68f2f44 100644
--- a/src/com/android/contacts/activities/GroupMembersActivity.java
+++ b/src/com/android/contacts/activities/GroupMembersActivity.java
@@ -36,6 +36,7 @@
import com.android.contacts.common.logging.ListEvent;
import com.android.contacts.common.logging.Logger;
import com.android.contacts.common.logging.ScreenEvent.ScreenType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.util.ImplicitIntentsUtil;
import com.android.contacts.group.GroupMembersFragment;
import com.android.contacts.group.GroupMetadata;
@@ -53,8 +54,7 @@
public class GroupMembersActivity extends ContactsDrawerActivity implements
ActionBarAdapter.Listener,
MultiSelectContactsListFragment.OnCheckBoxListActionListener,
- GroupMembersFragment.GroupMembersListener,
- GroupNameEditDialogFragment.Listener {
+ GroupMembersFragment.GroupMembersListener {
private static final String TAG = "GroupMembers";
@@ -382,8 +382,11 @@
return true;
}
case R.id.menu_rename_group: {
- GroupNameEditDialogFragment.showUpdateDialog(
- getFragmentManager(), TAG_GROUP_NAME_EDIT_DIALOG, mGroupMetadata.groupName);
+ GroupNameEditDialogFragment.newInstanceForUpdate(
+ new AccountWithDataSet(mGroupMetadata.accountName,
+ mGroupMetadata.accountType, mGroupMetadata.dataSet),
+ ACTION_UPDATE_GROUP, mGroupMetadata.groupId, mGroupMetadata.groupName)
+ .show(getFragmentManager(), TAG_GROUP_NAME_EDIT_DIALOG);
return true;
}
case R.id.menu_delete_group: {
@@ -567,23 +570,6 @@
mActionBarAdapter.setSelectionMode(false);
}
- // GroupNameEditDialogFragment.Listener callbacks
-
- @Override
- public void onGroupNameEdit(String groupName, boolean isInsert) {
- if (isInsert) {
- super.onGroupNameEdit(groupName, isInsert);
- return;
- }
- startService(ContactSaveService.createGroupRenameIntent(this,
- mGroupMetadata.groupId, groupName, GroupMembersActivity.class,
- ACTION_UPDATE_GROUP));
- }
-
- @Override
- public void onGroupNameEditCancelled() {
- }
-
// GroupMembersFragment callbacks
@Override
diff --git a/src/com/android/contacts/common/CallUtil.java b/src/com/android/contacts/common/CallUtil.java
new file mode 100644
index 0000000..88fca92
--- /dev/null
+++ b/src/com/android/contacts/common/CallUtil.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2015 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.common;
+
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.PhoneAccountSdkCompat;
+import com.android.contacts.common.util.PermissionsUtil;
+import com.android.contacts.common.util.PhoneNumberHelper;
+import com.android.phone.common.PhoneConstants;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telecom.VideoProfile;
+import android.text.TextUtils;
+
+import java.util.List;
+
+/**
+ * Utilities related to calls that can be used by non system apps. These
+ * use {@link Intent#ACTION_CALL} instead of ACTION_CALL_PRIVILEGED.
+ *
+ * The privileged version of this util exists inside Dialer.
+ */
+public class CallUtil {
+
+ /**
+ * Indicates that the video calling is not available.
+ */
+ public static final int VIDEO_CALLING_DISABLED = 0;
+
+ /**
+ * Indicates that video calling is enabled, regardless of presence status.
+ */
+ public static final int VIDEO_CALLING_ENABLED = 1;
+
+ /**
+ * Indicates that video calling is enabled, but the availability of video call affordances is
+ * determined by the presence status associated with contacts.
+ */
+ public static final int VIDEO_CALLING_PRESENCE = 2;
+
+ /**
+ * Return an Intent for making a phone call. Scheme (e.g. tel, sip) will be determined
+ * automatically.
+ */
+ public static Intent getCallWithSubjectIntent(String number,
+ PhoneAccountHandle phoneAccountHandle, String callSubject) {
+
+ final Intent intent = getCallIntent(getCallUri(number));
+ intent.putExtra(TelecomManager.EXTRA_CALL_SUBJECT, callSubject);
+ if (phoneAccountHandle != null) {
+ intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
+ }
+ return intent;
+ }
+
+ /**
+ * Return an Intent for making a phone call. Scheme (e.g. tel, sip) will be determined
+ * automatically.
+ */
+ public static Intent getCallIntent(String number) {
+ return getCallIntent(getCallUri(number));
+ }
+
+ /**
+ * Return an Intent for making a phone call. A given Uri will be used as is (without any
+ * sanity check).
+ */
+ public static Intent getCallIntent(Uri uri) {
+ return new Intent(Intent.ACTION_CALL, uri);
+ }
+
+ /**
+ * A variant of {@link #getCallIntent} for starting a video call.
+ */
+ public static Intent getVideoCallIntent(String number, String callOrigin) {
+ final Intent intent = new Intent(Intent.ACTION_CALL, getCallUri(number));
+ intent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
+ VideoProfile.STATE_BIDIRECTIONAL);
+ if (!TextUtils.isEmpty(callOrigin)) {
+ intent.putExtra(PhoneConstants.EXTRA_CALL_ORIGIN, callOrigin);
+ }
+ return intent;
+ }
+
+ /**
+ * Return Uri with an appropriate scheme, accepting both SIP and usual phone call
+ * numbers.
+ */
+ public static Uri getCallUri(String number) {
+ if (PhoneNumberHelper.isUriNumber(number)) {
+ return Uri.fromParts(PhoneAccount.SCHEME_SIP, number, null);
+ }
+ return Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
+ }
+
+ /**
+ * @return Uri that directly dials a user's voicemail inbox.
+ */
+ public static Uri getVoicemailUri() {
+ return Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "", null);
+ }
+
+ /**
+ * Determines if video calling is available, and if so whether presence checking is available
+ * as well.
+ *
+ * Returns a bitmask with {@link #VIDEO_CALLING_ENABLED} to indicate that video calling is
+ * available, and {@link #VIDEO_CALLING_PRESENCE} if presence indication is also available.
+ *
+ * @param context The context
+ * @return A bit-mask describing the current video capabilities.
+ */
+ public static int getVideoCallingAvailability(Context context) {
+ if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE)
+ || !CompatUtils.isVideoCompatible()) {
+ return VIDEO_CALLING_DISABLED;
+ }
+ TelecomManager telecommMgr = (TelecomManager)
+ context.getSystemService(Context.TELECOM_SERVICE);
+ if (telecommMgr == null) {
+ return VIDEO_CALLING_DISABLED;
+ }
+
+ List<PhoneAccountHandle> accountHandles = telecommMgr.getCallCapablePhoneAccounts();
+ for (PhoneAccountHandle accountHandle : accountHandles) {
+ PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle);
+ if (account != null) {
+ if (account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
+ // Builds prior to N do not have presence support.
+ if (!CompatUtils.isVideoPresenceCompatible()) {
+ return VIDEO_CALLING_ENABLED;
+ }
+
+ int videoCapabilities = VIDEO_CALLING_ENABLED;
+ if (account.hasCapabilities(
+ PhoneAccountSdkCompat.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)) {
+ videoCapabilities |= VIDEO_CALLING_PRESENCE;
+ }
+ return videoCapabilities;
+ }
+ }
+ }
+ return VIDEO_CALLING_DISABLED;
+ }
+
+ /**
+ * Determines if one of the call capable phone accounts defined supports video calling.
+ *
+ * @param context The context.
+ * @return {@code true} if one of the call capable phone accounts supports video calling,
+ * {@code false} otherwise.
+ */
+ public static boolean isVideoEnabled(Context context) {
+ return (getVideoCallingAvailability(context) & VIDEO_CALLING_ENABLED) != 0;
+ }
+
+ /**
+ * Determines if one of the call capable phone accounts defined supports calling with a subject
+ * specified.
+ *
+ * @param context The context.
+ * @return {@code true} if one of the call capable phone accounts supports calling with a
+ * subject specified, {@code false} otherwise.
+ */
+ public static boolean isCallWithSubjectSupported(Context context) {
+ if (!PermissionsUtil.hasPermission(context, android.Manifest.permission.READ_PHONE_STATE)
+ || !CompatUtils.isCallSubjectCompatible()) {
+ return false;
+ }
+ TelecomManager telecommMgr = (TelecomManager)
+ context.getSystemService(Context.TELECOM_SERVICE);
+ if (telecommMgr == null) {
+ return false;
+ }
+
+ List<PhoneAccountHandle> accountHandles = telecommMgr.getCallCapablePhoneAccounts();
+ for (PhoneAccountHandle accountHandle : accountHandles) {
+ PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle);
+ if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/com/android/contacts/common/ClipboardUtils.java b/src/com/android/contacts/common/ClipboardUtils.java
new file mode 100644
index 0000000..27af963
--- /dev/null
+++ b/src/com/android/contacts/common/ClipboardUtils.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012 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.common;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.text.TextUtils;
+import android.widget.Toast;
+
+public class ClipboardUtils {
+ private static final String TAG = "ClipboardUtils";
+
+ private ClipboardUtils() { }
+
+ /**
+ * Copy a text to clipboard.
+ *
+ * @param context Context
+ * @param label Label to show to the user describing this clip.
+ * @param text Text to copy.
+ * @param showToast If {@code true}, a toast is shown to the user.
+ */
+ public static void copyText(Context context, CharSequence label, CharSequence text,
+ boolean showToast) {
+ if (TextUtils.isEmpty(text)) return;
+
+ ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(
+ Context.CLIPBOARD_SERVICE);
+ ClipData clipData = ClipData.newPlainText(label == null ? "" : label, text);
+ clipboardManager.setPrimaryClip(clipData);
+
+ if (showToast) {
+ String toastText = context.getString(R.string.toast_text_copied);
+ Toast.makeText(context, toastText, Toast.LENGTH_SHORT).show();
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/Collapser.java b/src/com/android/contacts/common/Collapser.java
new file mode 100644
index 0000000..1ab63c5
--- /dev/null
+++ b/src/com/android/contacts/common/Collapser.java
@@ -0,0 +1,96 @@
+/*
+ * 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.common;
+
+import android.content.Context;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * 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() {}
+
+ /*
+ * The Collapser uses an n^2 algorithm so we don't want it to run on
+ * lists beyond a certain size. This specifies the maximum size to collapse.
+ */
+ private static final int MAX_LISTSIZE_TO_COLLAPSE = 20;
+
+ /*
+ * 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 void collapseWith(T t);
+ public boolean shouldCollapseWith(T t, Context context);
+
+ }
+
+ /**
+ * Collapses a list of Collapsible items into a list of collapsed items. Items are collapsed
+ * if {@link Collapsible#shouldCollapseWith(Object)} returns true, and are collapsed
+ * through the {@Link Collapsible#collapseWith(Object)} function implemented by the data item.
+ *
+ * @param list List of Objects of type <T extends Collapsible<T>> to be collapsed.
+ */
+ public static <T extends Collapsible<T>> void collapseList(List<T> list, Context context) {
+
+ int listSize = list.size();
+ // The algorithm below is n^2 so don't run on long lists
+ if (listSize > MAX_LISTSIZE_TO_COLLAPSE) {
+ return;
+ }
+
+ 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, context)) {
+ iItem.collapseWith(jItem);
+ list.set(j, null);
+ } else if (jItem.shouldCollapseWith(iItem, context)) {
+ jItem.collapseWith(iItem);
+ list.set(i, null);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // 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/common/ContactPhotoManager.java b/src/com/android/contacts/common/ContactPhotoManager.java
new file mode 100644
index 0000000..623b207
--- /dev/null
+++ b/src/com/android/contacts/common/ContactPhotoManager.java
@@ -0,0 +1,1720 @@
+/*
+ * Copyright (C) 2010 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.common;
+
+import android.app.ActivityManager;
+import android.content.ComponentCallbacks2;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.TransitionDrawable;
+import android.media.ThumbnailUtils;
+import android.net.TrafficStats;
+import android.net.Uri;
+import android.net.Uri.Builder;
+import android.os.Handler;
+import android.os.Handler.Callback;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Contacts.Photo;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Directory;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.LruCache;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import com.android.contacts.common.lettertiles.LetterTileDrawable;
+import com.android.contacts.common.util.BitmapUtil;
+import com.android.contacts.common.util.PermissionsUtil;
+import com.android.contacts.common.util.TrafficStatsTags;
+import com.android.contacts.common.util.UriUtils;
+import com.android.contactsbind.util.UserAgentGenerator;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Asynchronously loads contact photos and maintains a cache of photos.
+ */
+public abstract class ContactPhotoManager implements ComponentCallbacks2 {
+ static final String TAG = "ContactPhotoManager";
+ static final boolean DEBUG = false; // Don't submit with true
+ static final boolean DEBUG_SIZES = false; // Don't submit with true
+
+ /** Contact type constants used for default letter images */
+ public static final int TYPE_PERSON = LetterTileDrawable.TYPE_PERSON;
+ public static final int TYPE_BUSINESS = LetterTileDrawable.TYPE_BUSINESS;
+ public static final int TYPE_VOICEMAIL = LetterTileDrawable.TYPE_VOICEMAIL;
+ public static final int TYPE_DEFAULT = LetterTileDrawable.TYPE_DEFAULT;
+
+ /** Scale and offset default constants used for default letter images */
+ public static final float SCALE_DEFAULT = 1.0f;
+ public static final float OFFSET_DEFAULT = 0.0f;
+
+ public static final boolean IS_CIRCULAR_DEFAULT = false;
+
+ /** Uri-related constants used for default letter images */
+ private static final String DISPLAY_NAME_PARAM_KEY = "display_name";
+ private static final String IDENTIFIER_PARAM_KEY = "identifier";
+ private static final String CONTACT_TYPE_PARAM_KEY = "contact_type";
+ private static final String SCALE_PARAM_KEY = "scale";
+ private static final String OFFSET_PARAM_KEY = "offset";
+ private static final String IS_CIRCULAR_PARAM_KEY = "is_circular";
+ private static final String DEFAULT_IMAGE_URI_SCHEME = "defaultimage";
+ private static final Uri DEFAULT_IMAGE_URI = Uri.parse(DEFAULT_IMAGE_URI_SCHEME + "://");
+
+ // Static field used to cache the default letter avatar drawable that is created
+ // using a null {@link DefaultImageRequest}
+ private static Drawable sDefaultLetterAvatar = null;
+
+ private static ContactPhotoManager sInstance;
+
+ /**
+ * Given a {@link DefaultImageRequest}, returns a {@link Drawable}, that when drawn, will
+ * draw a letter tile avatar based on the request parameters defined in the
+ * {@link DefaultImageRequest}.
+ */
+ public static Drawable getDefaultAvatarDrawableForContact(Resources resources, boolean hires,
+ DefaultImageRequest defaultImageRequest) {
+ if (defaultImageRequest == null) {
+ if (sDefaultLetterAvatar == null) {
+ // Cache and return the letter tile drawable that is created by a null request,
+ // so that it doesn't have to be recreated every time it is requested again.
+ sDefaultLetterAvatar = LetterTileDefaultImageProvider.getDefaultImageForContact(
+ resources, null);
+ }
+ return sDefaultLetterAvatar;
+ }
+ return LetterTileDefaultImageProvider.getDefaultImageForContact(resources,
+ defaultImageRequest);
+ }
+
+ /**
+ * Given a {@link DefaultImageRequest}, returns an Uri that can be used to request a
+ * letter tile avatar when passed to the {@link ContactPhotoManager}. The internal
+ * implementation of this uri is not guaranteed to remain the same across application
+ * versions, so the actual uri should never be persisted in long-term storage and reused.
+ *
+ * @param request A {@link DefaultImageRequest} object with the fields configured
+ * to return a
+ * @return A Uri that when later passed to the {@link ContactPhotoManager} via
+ * {@link #loadPhoto(ImageView, Uri, int, boolean, DefaultImageRequest)}, can be
+ * used to request a default contact image, drawn as a letter tile using the
+ * parameters as configured in the provided {@link DefaultImageRequest}
+ */
+ public static Uri getDefaultAvatarUriForContact(DefaultImageRequest request) {
+ final Builder builder = DEFAULT_IMAGE_URI.buildUpon();
+ if (request != null) {
+ if (!TextUtils.isEmpty(request.displayName)) {
+ builder.appendQueryParameter(DISPLAY_NAME_PARAM_KEY, request.displayName);
+ }
+ if (!TextUtils.isEmpty(request.identifier)) {
+ builder.appendQueryParameter(IDENTIFIER_PARAM_KEY, request.identifier);
+ }
+ if (request.contactType != TYPE_DEFAULT) {
+ builder.appendQueryParameter(CONTACT_TYPE_PARAM_KEY,
+ String.valueOf(request.contactType));
+ }
+ if (request.scale != SCALE_DEFAULT) {
+ builder.appendQueryParameter(SCALE_PARAM_KEY, String.valueOf(request.scale));
+ }
+ if (request.offset != OFFSET_DEFAULT) {
+ builder.appendQueryParameter(OFFSET_PARAM_KEY, String.valueOf(request.offset));
+ }
+ if (request.isCircular != IS_CIRCULAR_DEFAULT) {
+ builder.appendQueryParameter(IS_CIRCULAR_PARAM_KEY,
+ String.valueOf(request.isCircular));
+ }
+
+ }
+ return builder.build();
+ }
+
+ /**
+ * Adds a business contact type encoded fragment to the URL. Used to ensure photo URLS
+ * from Nearby Places can be identified as business photo URLs rather than URLs for personal
+ * contact photos.
+ *
+ * @param photoUrl The photo URL to modify.
+ * @return URL with the contact type parameter added and set to TYPE_BUSINESS.
+ */
+ public static String appendBusinessContactType(String photoUrl) {
+ Uri uri = Uri.parse(photoUrl);
+ Builder builder = uri.buildUpon();
+ builder.encodedFragment(String.valueOf(TYPE_BUSINESS));
+ return builder.build().toString();
+ }
+
+ /**
+ * Removes the contact type information stored in the photo URI encoded fragment.
+ *
+ * @param photoUri The photo URI to remove the contact type from.
+ * @return The photo URI with contact type removed.
+ */
+ public static Uri removeContactType(Uri photoUri) {
+ String encodedFragment = photoUri.getEncodedFragment();
+ if (!TextUtils.isEmpty(encodedFragment)) {
+ Builder builder = photoUri.buildUpon();
+ builder.encodedFragment(null);
+ return builder.build();
+ }
+ return photoUri;
+ }
+
+ /**
+ * Inspects a photo URI to determine if the photo URI represents a business.
+ *
+ * @param photoUri The URI to inspect.
+ * @return Whether the URI represents a business photo or not.
+ */
+ public static boolean isBusinessContactUri(Uri photoUri) {
+ if (photoUri == null) {
+ return false;
+ }
+
+ String encodedFragment = photoUri.getEncodedFragment();
+ return !TextUtils.isEmpty(encodedFragment)
+ && encodedFragment.equals(String.valueOf(TYPE_BUSINESS));
+ }
+
+ protected static DefaultImageRequest getDefaultImageRequestFromUri(Uri uri) {
+ final DefaultImageRequest request = new DefaultImageRequest(
+ uri.getQueryParameter(DISPLAY_NAME_PARAM_KEY),
+ uri.getQueryParameter(IDENTIFIER_PARAM_KEY), false);
+ try {
+ String contactType = uri.getQueryParameter(CONTACT_TYPE_PARAM_KEY);
+ if (!TextUtils.isEmpty(contactType)) {
+ request.contactType = Integer.valueOf(contactType);
+ }
+
+ String scale = uri.getQueryParameter(SCALE_PARAM_KEY);
+ if (!TextUtils.isEmpty(scale)) {
+ request.scale = Float.valueOf(scale);
+ }
+
+ String offset = uri.getQueryParameter(OFFSET_PARAM_KEY);
+ if (!TextUtils.isEmpty(offset)) {
+ request.offset = Float.valueOf(offset);
+ }
+
+ String isCircular = uri.getQueryParameter(IS_CIRCULAR_PARAM_KEY);
+ if (!TextUtils.isEmpty(isCircular)) {
+ request.isCircular = Boolean.valueOf(isCircular);
+ }
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Invalid DefaultImageRequest image parameters provided, ignoring and using "
+ + "defaults.");
+ }
+
+ return request;
+ }
+
+ protected boolean isDefaultImageUri(Uri uri) {
+ return DEFAULT_IMAGE_URI_SCHEME.equals(uri.getScheme());
+ }
+
+ /**
+ * Contains fields used to contain contact details and other user-defined settings that might
+ * be used by the ContactPhotoManager to generate a default contact image. This contact image
+ * takes the form of a letter or bitmap drawn on top of a colored tile.
+ */
+ public static class DefaultImageRequest {
+ /**
+ * The contact's display name. The display name is used to
+ */
+ public String displayName;
+
+ /**
+ * A unique and deterministic string that can be used to identify this contact. This is
+ * usually the contact's lookup key, but other contact details can be used as well,
+ * especially for non-local or temporary contacts that might not have a lookup key. This
+ * is used to determine the color of the tile.
+ */
+ public String identifier;
+
+ /**
+ * The type of this contact. This contact type may be used to decide the kind of
+ * image to use in the case where a unique letter cannot be generated from the contact's
+ * display name and identifier. See:
+ * {@link #TYPE_PERSON}
+ * {@link #TYPE_BUSINESS}
+ * {@link #TYPE_PERSON}
+ * {@link #TYPE_DEFAULT}
+ */
+ public int contactType = TYPE_DEFAULT;
+
+ /**
+ * The amount to scale the letter or bitmap to, as a ratio of its default size (from a
+ * range of 0.0f to 2.0f). The default value is 1.0f.
+ */
+ public float scale = SCALE_DEFAULT;
+
+ /**
+ * The amount to vertically offset the letter or image to within the tile.
+ * The provided offset must be within the range of -0.5f to 0.5f.
+ * If set to -0.5f, the letter will be shifted upwards by 0.5 times the height of the canvas
+ * it is being drawn on, which means it will be drawn with the center of the letter starting
+ * at the top edge of the canvas.
+ * If set to 0.5f, the letter will be shifted downwards by 0.5 times the height of the
+ * canvas it is being drawn on, which means it will be drawn with the center of the letter
+ * starting at the bottom edge of the canvas.
+ * The default is 0.0f, which means the letter is drawn in the exact vertical center of
+ * the tile.
+ */
+ public float offset = OFFSET_DEFAULT;
+
+ /**
+ * Whether or not to draw the default image as a circle, instead of as a square/rectangle.
+ */
+ public boolean isCircular = false;
+
+ /**
+ * Used to indicate that a drawable that represents a contact without any contact details
+ * should be returned.
+ */
+ public static DefaultImageRequest EMPTY_DEFAULT_IMAGE_REQUEST = new DefaultImageRequest();
+
+ /**
+ * Used to indicate that a drawable that represents a business without a business photo
+ * should be returned.
+ */
+ public static DefaultImageRequest EMPTY_DEFAULT_BUSINESS_IMAGE_REQUEST =
+ new DefaultImageRequest(null, null, TYPE_BUSINESS, false);
+
+ /**
+ * Used to indicate that a circular drawable that represents a contact without any contact
+ * details should be returned.
+ */
+ public static DefaultImageRequest EMPTY_CIRCULAR_DEFAULT_IMAGE_REQUEST =
+ new DefaultImageRequest(null, null, true);
+
+ /**
+ * Used to indicate that a circular drawable that represents a business without a business
+ * photo should be returned.
+ */
+ public static DefaultImageRequest EMPTY_CIRCULAR_BUSINESS_IMAGE_REQUEST =
+ new DefaultImageRequest(null, null, TYPE_BUSINESS, true);
+
+ public DefaultImageRequest() {
+ }
+
+ public DefaultImageRequest(String displayName, String identifier, boolean isCircular) {
+ this(displayName, identifier, TYPE_DEFAULT, SCALE_DEFAULT, OFFSET_DEFAULT, isCircular);
+ }
+
+ public DefaultImageRequest(String displayName, String identifier, int contactType,
+ boolean isCircular) {
+ this(displayName, identifier, contactType, SCALE_DEFAULT, OFFSET_DEFAULT, isCircular);
+ }
+
+ public DefaultImageRequest(String displayName, String identifier, int contactType,
+ float scale, float offset, boolean isCircular) {
+ this.displayName = displayName;
+ this.identifier = identifier;
+ this.contactType = contactType;
+ this.scale = scale;
+ this.offset = offset;
+ this.isCircular = isCircular;
+ }
+ }
+
+ public static abstract class DefaultImageProvider {
+ /**
+ * Applies the default avatar to the ImageView. Extent is an indicator for the size (width
+ * or height). If darkTheme is set, the avatar is one that looks better on dark background
+ *
+ * @param defaultImageRequest {@link DefaultImageRequest} object that specifies how a
+ * default letter tile avatar should be drawn.
+ */
+ public abstract void applyDefaultImage(ImageView view, int extent, boolean darkTheme,
+ DefaultImageRequest defaultImageRequest);
+ }
+
+ /**
+ * A default image provider that applies a letter tile consisting of a colored background
+ * and a letter in the foreground as the default image for a contact. The color of the
+ * background and the type of letter is decided based on the contact's details.
+ */
+ private static class LetterTileDefaultImageProvider extends DefaultImageProvider {
+ @Override
+ public void applyDefaultImage(ImageView view, int extent, boolean darkTheme,
+ DefaultImageRequest defaultImageRequest) {
+ final Drawable drawable = getDefaultImageForContact(view.getResources(),
+ defaultImageRequest);
+ view.setImageDrawable(drawable);
+ }
+
+ public static Drawable getDefaultImageForContact(Resources resources,
+ DefaultImageRequest defaultImageRequest) {
+ final LetterTileDrawable drawable = new LetterTileDrawable(resources);
+ if (defaultImageRequest != null) {
+ // If the contact identifier is null or empty, fallback to the
+ // displayName. In that case, use {@code null} for the contact's
+ // display name so that a default bitmap will be used instead of a
+ // letter
+ if (TextUtils.isEmpty(defaultImageRequest.identifier)) {
+ drawable.setLetterAndColorFromContactDetails(null,
+ defaultImageRequest.displayName);
+ } else {
+ drawable.setLetterAndColorFromContactDetails(defaultImageRequest.displayName,
+ defaultImageRequest.identifier);
+ }
+ drawable.setContactType(defaultImageRequest.contactType);
+ drawable.setScale(defaultImageRequest.scale);
+ drawable.setOffset(defaultImageRequest.offset);
+ drawable.setIsCircular(defaultImageRequest.isCircular);
+ }
+ return drawable;
+ }
+ }
+
+ private static class BlankDefaultImageProvider extends DefaultImageProvider {
+ private static Drawable sDrawable;
+
+ @Override
+ public void applyDefaultImage(ImageView view, int extent, boolean darkTheme,
+ DefaultImageRequest defaultImageRequest) {
+ if (sDrawable == null) {
+ Context context = view.getContext();
+ sDrawable = new ColorDrawable(context.getResources().getColor(
+ R.color.image_placeholder));
+ }
+ view.setImageDrawable(sDrawable);
+ }
+ }
+
+ public static DefaultImageProvider DEFAULT_AVATAR = new LetterTileDefaultImageProvider();
+
+ public static final DefaultImageProvider DEFAULT_BLANK = new BlankDefaultImageProvider();
+
+ public static ContactPhotoManager getInstance(Context context) {
+ if (sInstance == null) {
+ Context applicationContext = context.getApplicationContext();
+ sInstance = createContactPhotoManager(applicationContext);
+ applicationContext.registerComponentCallbacks(sInstance);
+ if (PermissionsUtil.hasContactsPermissions(context)) {
+ sInstance.preloadPhotosInBackground();
+ }
+ }
+ return sInstance;
+ }
+
+ public static synchronized ContactPhotoManager createContactPhotoManager(Context context) {
+ return new ContactPhotoManagerImpl(context);
+ }
+
+ @VisibleForTesting
+ public static void injectContactPhotoManagerForTesting(ContactPhotoManager photoManager) {
+ sInstance = photoManager;
+ }
+
+ /**
+ * Load thumbnail image into the supplied image view. If the photo is already cached,
+ * it is displayed immediately. Otherwise a request is sent to load the photo
+ * from the database.
+ */
+ public abstract void loadThumbnail(ImageView view, long photoId, boolean darkTheme,
+ boolean isCircular, DefaultImageRequest defaultImageRequest,
+ DefaultImageProvider defaultProvider);
+
+ /**
+ * Calls {@link #loadThumbnail(ImageView, long, boolean, DefaultImageRequest,
+ * DefaultImageProvider)} using the {@link DefaultImageProvider} {@link #DEFAULT_AVATAR}.
+ */
+ public final void loadThumbnail(ImageView view, long photoId, boolean darkTheme,
+ boolean isCircular, DefaultImageRequest defaultImageRequest) {
+ loadThumbnail(view, photoId, darkTheme, isCircular, defaultImageRequest, DEFAULT_AVATAR);
+ }
+
+
+ /**
+ * Load photo into the supplied image view. If the photo is already cached,
+ * it is displayed immediately. Otherwise a request is sent to load the photo
+ * from the location specified by the URI.
+ *
+ * @param view The target view
+ * @param photoUri The uri of the photo to load
+ * @param requestedExtent Specifies an approximate Max(width, height) of the targetView.
+ * This is useful if the source image can be a lot bigger that the target, so that the decoding
+ * is done using efficient sampling. If requestedExtent is specified, no sampling of the image
+ * is performed
+ * @param darkTheme Whether the background is dark. This is used for default avatars
+ * @param defaultImageRequest {@link DefaultImageRequest} object that specifies how a default
+ * letter tile avatar should be drawn.
+ * @param defaultProvider The provider of default avatars (this is used if photoUri doesn't
+ * refer to an existing image)
+ */
+ public abstract void loadPhoto(ImageView view, Uri photoUri, int requestedExtent,
+ boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
+ DefaultImageProvider defaultProvider);
+
+ /**
+ * Calls {@link #loadPhoto(ImageView, Uri, int, boolean, DefaultImageRequest,
+ * DefaultImageProvider)} with {@link #DEFAULT_AVATAR} and {@code null} display names and
+ * lookup keys.
+ *
+ * @param defaultImageRequest {@link DefaultImageRequest} object that specifies how a default
+ * letter tile avatar should be drawn.
+ */
+ public final void loadPhoto(ImageView view, Uri photoUri, int requestedExtent,
+ boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest) {
+ loadPhoto(view, photoUri, requestedExtent, darkTheme, isCircular,
+ defaultImageRequest, DEFAULT_AVATAR);
+ }
+
+ /**
+ * Calls {@link #loadPhoto(ImageView, Uri, boolean, boolean, DefaultImageRequest,
+ * DefaultImageProvider)} with {@link #DEFAULT_AVATAR} and with the assumption, that
+ * the image is a thumbnail.
+ *
+ * @param defaultImageRequest {@link DefaultImageRequest} object that specifies how a default
+ * letter tile avatar should be drawn.
+ */
+ public final void loadDirectoryPhoto(ImageView view, Uri photoUri, boolean darkTheme,
+ boolean isCircular, DefaultImageRequest defaultImageRequest) {
+ loadPhoto(view, photoUri, -1, darkTheme, isCircular, defaultImageRequest, DEFAULT_AVATAR);
+ }
+
+ /**
+ * Remove photo from the supplied image view. This also cancels current pending load request
+ * inside this photo manager.
+ */
+ public abstract void removePhoto(ImageView view);
+
+ /**
+ * Cancels all pending requests to load photos asynchronously.
+ */
+ public abstract void cancelPendingRequests(View fragmentRootView);
+
+ /**
+ * Temporarily stops loading photos from the database.
+ */
+ public abstract void pause();
+
+ /**
+ * Resumes loading photos from the database.
+ */
+ public abstract void resume();
+
+ /**
+ * Marks all cached photos for reloading. We can continue using cache but should
+ * also make sure the photos haven't changed in the background and notify the views
+ * if so.
+ */
+ public abstract void refreshCache();
+
+ /**
+ * Stores the given bitmap directly in the LRU bitmap cache.
+ * @param photoUri The URI of the photo (for future requests).
+ * @param bitmap The bitmap.
+ * @param photoBytes The bytes that were parsed to create the bitmap.
+ */
+ public abstract void cacheBitmap(Uri photoUri, Bitmap bitmap, byte[] photoBytes);
+
+ /**
+ * Initiates a background process that over time will fill up cache with
+ * preload photos.
+ */
+ public abstract void preloadPhotosInBackground();
+
+ // ComponentCallbacks2
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ }
+
+ // ComponentCallbacks2
+ @Override
+ public void onLowMemory() {
+ }
+
+ // ComponentCallbacks2
+ @Override
+ public void onTrimMemory(int level) {
+ }
+}
+
+class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback {
+ private static final String LOADER_THREAD_NAME = "ContactPhotoLoader";
+
+ private static final int FADE_TRANSITION_DURATION = 200;
+
+ /**
+ * Type of message sent by the UI thread to itself to indicate that some photos
+ * need to be loaded.
+ */
+ private static final int MESSAGE_REQUEST_LOADING = 1;
+
+ /**
+ * Type of message sent by the loader thread to indicate that some photos have
+ * been loaded.
+ */
+ private static final int MESSAGE_PHOTOS_LOADED = 2;
+
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+ private static final String[] COLUMNS = new String[] { Photo._ID, Photo.PHOTO };
+
+ /**
+ * Dummy object used to indicate that a bitmap for a given key could not be stored in the
+ * cache.
+ */
+ private static final BitmapHolder BITMAP_UNAVAILABLE;
+
+ static {
+ BITMAP_UNAVAILABLE = new BitmapHolder(new byte[0], 0);
+ BITMAP_UNAVAILABLE.bitmapRef = new SoftReference<Bitmap>(null);
+ }
+
+ /**
+ * Maintains the state of a particular photo.
+ */
+ private static class BitmapHolder {
+ final byte[] bytes;
+ final int originalSmallerExtent;
+
+ volatile boolean fresh;
+ Bitmap bitmap;
+ Reference<Bitmap> bitmapRef;
+ int decodedSampleSize;
+
+ public BitmapHolder(byte[] bytes, int originalSmallerExtent) {
+ this.bytes = bytes;
+ this.fresh = true;
+ this.originalSmallerExtent = originalSmallerExtent;
+ }
+ }
+
+ private final Context mContext;
+
+ /**
+ * An LRU cache for bitmap holders. The cache contains bytes for photos just
+ * as they come from the database. Each holder has a soft reference to the
+ * actual bitmap.
+ */
+ private final LruCache<Object, BitmapHolder> mBitmapHolderCache;
+
+ /**
+ * {@code true} if ALL entries in {@link #mBitmapHolderCache} are NOT fresh.
+ */
+ private volatile boolean mBitmapHolderCacheAllUnfresh = true;
+
+ /**
+ * Cache size threshold at which bitmaps will not be preloaded.
+ */
+ private final int mBitmapHolderCacheRedZoneBytes;
+
+ /**
+ * Level 2 LRU cache for bitmaps. This is a smaller cache that holds
+ * the most recently used bitmaps to save time on decoding
+ * them from bytes (the bytes are stored in {@link #mBitmapHolderCache}.
+ */
+ private final LruCache<Object, Bitmap> mBitmapCache;
+
+ /**
+ * A map from ImageView to the corresponding photo ID or uri, encapsulated in a request.
+ * The request may swapped out before the photo loading request is started.
+ */
+ private final ConcurrentHashMap<ImageView, Request> mPendingRequests =
+ new ConcurrentHashMap<ImageView, Request>();
+
+ /**
+ * Handler for messages sent to the UI thread.
+ */
+ private final Handler mMainThreadHandler = new Handler(this);
+
+ /**
+ * Thread responsible for loading photos from the database. Created upon
+ * the first request.
+ */
+ private LoaderThread mLoaderThread;
+
+ /**
+ * A gate to make sure we only send one instance of MESSAGE_PHOTOS_NEEDED at a time.
+ */
+ private boolean mLoadingRequested;
+
+ /**
+ * Flag indicating if the image loading is paused.
+ */
+ private boolean mPaused;
+
+ /** Cache size for {@link #mBitmapHolderCache} for devices with "large" RAM. */
+ private static final int HOLDER_CACHE_SIZE = 2000000;
+
+ /** Cache size for {@link #mBitmapCache} for devices with "large" RAM. */
+ private static final int BITMAP_CACHE_SIZE = 36864 * 48; // 1728K
+
+ /** Height/width of a thumbnail image */
+ private static int mThumbnailSize;
+
+ /** For debug: How many times we had to reload cached photo for a stale entry */
+ private final AtomicInteger mStaleCacheOverwrite = new AtomicInteger();
+
+ /** For debug: How many times we had to reload cached photo for a fresh entry. Should be 0. */
+ private final AtomicInteger mFreshCacheOverwrite = new AtomicInteger();
+
+ /**
+ * The user agent string to use when loading URI based photos.
+ */
+ private String mUserAgent;
+
+ public ContactPhotoManagerImpl(Context context) {
+ mContext = context;
+
+ final ActivityManager am = ((ActivityManager) context.getSystemService(
+ Context.ACTIVITY_SERVICE));
+
+ final float cacheSizeAdjustment = (am.isLowRamDevice()) ? 0.5f : 1.0f;
+
+ final int bitmapCacheSize = (int) (cacheSizeAdjustment * BITMAP_CACHE_SIZE);
+ mBitmapCache = new LruCache<Object, Bitmap>(bitmapCacheSize) {
+ @Override protected int sizeOf(Object key, Bitmap value) {
+ return value.getByteCount();
+ }
+
+ @Override protected void entryRemoved(
+ boolean evicted, Object key, Bitmap oldValue, Bitmap newValue) {
+ if (DEBUG) dumpStats();
+ }
+ };
+ final int holderCacheSize = (int) (cacheSizeAdjustment * HOLDER_CACHE_SIZE);
+ mBitmapHolderCache = new LruCache<Object, BitmapHolder>(holderCacheSize) {
+ @Override protected int sizeOf(Object key, BitmapHolder value) {
+ return value.bytes != null ? value.bytes.length : 0;
+ }
+
+ @Override protected void entryRemoved(
+ boolean evicted, Object key, BitmapHolder oldValue, BitmapHolder newValue) {
+ if (DEBUG) dumpStats();
+ }
+ };
+ mBitmapHolderCacheRedZoneBytes = (int) (holderCacheSize * 0.75);
+ Log.i(TAG, "Cache adj: " + cacheSizeAdjustment);
+ if (DEBUG) {
+ Log.d(TAG, "Cache size: " + btk(mBitmapHolderCache.maxSize())
+ + " + " + btk(mBitmapCache.maxSize()));
+ }
+
+ mThumbnailSize = context.getResources().getDimensionPixelSize(
+ R.dimen.contact_browser_list_item_photo_size);
+
+ // Get a user agent string to use for URI photo requests.
+ mUserAgent = UserAgentGenerator.getUserAgent(context);
+ if (mUserAgent == null) {
+ mUserAgent = "";
+ }
+ }
+
+ /** Converts bytes to K bytes, rounding up. Used only for debug log. */
+ private static String btk(int bytes) {
+ return ((bytes + 1023) / 1024) + "K";
+ }
+
+ private static final int safeDiv(int dividend, int divisor) {
+ return (divisor == 0) ? 0 : (dividend / divisor);
+ }
+
+ /**
+ * Dump cache stats on logcat.
+ */
+ private void dumpStats() {
+ if (!DEBUG) return;
+ {
+ int numHolders = 0;
+ int rawBytes = 0;
+ int bitmapBytes = 0;
+ int numBitmaps = 0;
+ for (BitmapHolder h : mBitmapHolderCache.snapshot().values()) {
+ numHolders++;
+ if (h.bytes != null) {
+ rawBytes += h.bytes.length;
+ }
+ Bitmap b = h.bitmapRef != null ? h.bitmapRef.get() : null;
+ if (b != null) {
+ numBitmaps++;
+ bitmapBytes += b.getByteCount();
+ }
+ }
+ Log.d(TAG, "L1: " + btk(rawBytes) + " + " + btk(bitmapBytes) + " = "
+ + btk(rawBytes + bitmapBytes) + ", " + numHolders + " holders, "
+ + numBitmaps + " bitmaps, avg: "
+ + btk(safeDiv(rawBytes, numHolders))
+ + "," + btk(safeDiv(bitmapBytes,numBitmaps)));
+ Log.d(TAG, "L1 Stats: " + mBitmapHolderCache.toString()
+ + ", overwrite: fresh=" + mFreshCacheOverwrite.get()
+ + " stale=" + mStaleCacheOverwrite.get());
+ }
+
+ {
+ int numBitmaps = 0;
+ int bitmapBytes = 0;
+ for (Bitmap b : mBitmapCache.snapshot().values()) {
+ numBitmaps++;
+ bitmapBytes += b.getByteCount();
+ }
+ Log.d(TAG, "L2: " + btk(bitmapBytes) + ", " + numBitmaps + " bitmaps"
+ + ", avg: " + btk(safeDiv(bitmapBytes, numBitmaps)));
+ // We don't get from L2 cache, so L2 stats is meaningless.
+ }
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ if (DEBUG) Log.d(TAG, "onTrimMemory: " + level);
+ if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
+ // Clear the caches. Note all pending requests will be removed too.
+ clear();
+ }
+ }
+
+ @Override
+ public void preloadPhotosInBackground() {
+ ensureLoaderThread();
+ mLoaderThread.requestPreloading();
+ }
+
+ @Override
+ public void loadThumbnail(ImageView view, long photoId, boolean darkTheme, boolean isCircular,
+ DefaultImageRequest defaultImageRequest, DefaultImageProvider defaultProvider) {
+ if (photoId == 0) {
+ // No photo is needed
+ defaultProvider.applyDefaultImage(view, -1, darkTheme, defaultImageRequest);
+ mPendingRequests.remove(view);
+ } else {
+ if (DEBUG) Log.d(TAG, "loadPhoto request: " + photoId);
+ loadPhotoByIdOrUri(view, Request.createFromThumbnailId(photoId, darkTheme, isCircular,
+ defaultProvider));
+ }
+ }
+
+ @Override
+ public void loadPhoto(ImageView view, Uri photoUri, int requestedExtent, boolean darkTheme,
+ boolean isCircular, DefaultImageRequest defaultImageRequest,
+ DefaultImageProvider defaultProvider) {
+ if (photoUri == null) {
+ // No photo is needed
+ defaultProvider.applyDefaultImage(view, requestedExtent, darkTheme,
+ defaultImageRequest);
+ mPendingRequests.remove(view);
+ } else {
+ if (DEBUG) Log.d(TAG, "loadPhoto request: " + photoUri);
+ if (isDefaultImageUri(photoUri)) {
+ createAndApplyDefaultImageForUri(view, photoUri, requestedExtent, darkTheme,
+ isCircular, defaultProvider);
+ } else {
+ loadPhotoByIdOrUri(view, Request.createFromUri(photoUri, requestedExtent,
+ darkTheme, isCircular, defaultProvider));
+ }
+ }
+ }
+
+ private void createAndApplyDefaultImageForUri(ImageView view, Uri uri, int requestedExtent,
+ boolean darkTheme, boolean isCircular, DefaultImageProvider defaultProvider) {
+ DefaultImageRequest request = getDefaultImageRequestFromUri(uri);
+ request.isCircular = isCircular;
+ defaultProvider.applyDefaultImage(view, requestedExtent, darkTheme, request);
+ }
+
+ private void loadPhotoByIdOrUri(ImageView view, Request request) {
+ boolean loaded = loadCachedPhoto(view, request, false);
+ if (loaded) {
+ mPendingRequests.remove(view);
+ } else {
+ mPendingRequests.put(view, request);
+ if (!mPaused) {
+ // Send a request to start loading photos
+ requestLoading();
+ }
+ }
+ }
+
+ @Override
+ public void removePhoto(ImageView view) {
+ view.setImageDrawable(null);
+ mPendingRequests.remove(view);
+ }
+
+
+ /**
+ * Cancels pending requests to load photos asynchronously for views inside
+ * {@param fragmentRootView}. If {@param fragmentRootView} is null, cancels all requests.
+ */
+ @Override
+ public void cancelPendingRequests(View fragmentRootView) {
+ if (fragmentRootView == null) {
+ mPendingRequests.clear();
+ return;
+ }
+ final Iterator<Entry<ImageView, Request>> iterator = mPendingRequests.entrySet().iterator();
+ while (iterator.hasNext()) {
+ final ImageView imageView = iterator.next().getKey();
+ // If an ImageView is orphaned (currently scrap) or a child of fragmentRootView, then
+ // we can safely remove its request.
+ if (imageView.getParent() == null || isChildView(fragmentRootView, imageView)) {
+ iterator.remove();
+ }
+ }
+ }
+
+ private static boolean isChildView(View parent, View potentialChild) {
+ return potentialChild.getParent() != null && (potentialChild.getParent() == parent || (
+ potentialChild.getParent() instanceof ViewGroup && isChildView(parent,
+ (ViewGroup) potentialChild.getParent())));
+ }
+
+ @Override
+ public void refreshCache() {
+ if (mBitmapHolderCacheAllUnfresh) {
+ if (DEBUG) Log.d(TAG, "refreshCache -- no fresh entries.");
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "refreshCache");
+ mBitmapHolderCacheAllUnfresh = true;
+ for (BitmapHolder holder : mBitmapHolderCache.snapshot().values()) {
+ if (holder != BITMAP_UNAVAILABLE) {
+ holder.fresh = false;
+ }
+ }
+ }
+
+ /**
+ * Checks if the photo is present in cache. If so, sets the photo on the view.
+ *
+ * @return false if the photo needs to be (re)loaded from the provider.
+ */
+ private boolean loadCachedPhoto(ImageView view, Request request, boolean fadeIn) {
+ BitmapHolder holder = mBitmapHolderCache.get(request.getKey());
+ if (holder == null) {
+ // The bitmap has not been loaded ==> show default avatar
+ request.applyDefaultImage(view, request.mIsCircular);
+ return false;
+ }
+
+ if (holder.bytes == null) {
+ request.applyDefaultImage(view, request.mIsCircular);
+ return holder.fresh;
+ }
+
+ Bitmap cachedBitmap = holder.bitmapRef == null ? null : holder.bitmapRef.get();
+ if (cachedBitmap == null) {
+ if (holder.bytes.length < 8 * 1024) {
+ // Small thumbnails are usually quick to inflate. Let's do that on the UI thread
+ inflateBitmap(holder, request.getRequestedExtent());
+ cachedBitmap = holder.bitmap;
+ if (cachedBitmap == null) return false;
+ } else {
+ // This is bigger data. Let's send that back to the Loader so that we can
+ // inflate this in the background
+ request.applyDefaultImage(view, request.mIsCircular);
+ return false;
+ }
+ }
+
+ final Drawable previousDrawable = view.getDrawable();
+ if (fadeIn && previousDrawable != null) {
+ final Drawable[] layers = new Drawable[2];
+ // Prevent cascade of TransitionDrawables.
+ if (previousDrawable instanceof TransitionDrawable) {
+ final TransitionDrawable previousTransitionDrawable =
+ (TransitionDrawable) previousDrawable;
+ layers[0] = previousTransitionDrawable.getDrawable(
+ previousTransitionDrawable.getNumberOfLayers() - 1);
+ } else {
+ layers[0] = previousDrawable;
+ }
+ layers[1] = getDrawableForBitmap(mContext.getResources(), cachedBitmap, request);
+ TransitionDrawable drawable = new TransitionDrawable(layers);
+ view.setImageDrawable(drawable);
+ drawable.startTransition(FADE_TRANSITION_DURATION);
+ } else {
+ view.setImageDrawable(
+ getDrawableForBitmap(mContext.getResources(), cachedBitmap, request));
+ }
+
+ // Put the bitmap in the LRU cache. But only do this for images that are small enough
+ // (we require that at least six of those can be cached at the same time)
+ if (cachedBitmap.getByteCount() < mBitmapCache.maxSize() / 6) {
+ mBitmapCache.put(request.getKey(), cachedBitmap);
+ }
+
+ // Soften the reference
+ holder.bitmap = null;
+
+ return holder.fresh;
+ }
+
+ /**
+ * Given a bitmap, returns a drawable that is configured to display the bitmap based on the
+ * specified request.
+ */
+ private Drawable getDrawableForBitmap(Resources resources, Bitmap bitmap, Request request) {
+ if (request.mIsCircular) {
+ final RoundedBitmapDrawable drawable =
+ RoundedBitmapDrawableFactory.create(resources, bitmap);
+ drawable.setAntiAlias(true);
+ drawable.setCornerRadius(bitmap.getHeight() / 2);
+ return drawable;
+ } else {
+ return new BitmapDrawable(resources, bitmap);
+ }
+ }
+
+ /**
+ * If necessary, decodes bytes stored in the holder to Bitmap. As long as the
+ * bitmap is held either by {@link #mBitmapCache} or by a soft reference in
+ * the holder, it will not be necessary to decode the bitmap.
+ */
+ private static void inflateBitmap(BitmapHolder holder, int requestedExtent) {
+ final int sampleSize =
+ BitmapUtil.findOptimalSampleSize(holder.originalSmallerExtent, requestedExtent);
+ byte[] bytes = holder.bytes;
+ if (bytes == null || bytes.length == 0) {
+ return;
+ }
+
+ if (sampleSize == holder.decodedSampleSize) {
+ // Check the soft reference. If will be retained if the bitmap is also
+ // in the LRU cache, so we don't need to check the LRU cache explicitly.
+ if (holder.bitmapRef != null) {
+ holder.bitmap = holder.bitmapRef.get();
+ if (holder.bitmap != null) {
+ return;
+ }
+ }
+ }
+
+ try {
+ Bitmap bitmap = BitmapUtil.decodeBitmapFromBytes(bytes, sampleSize);
+
+ // TODO: As a temporary workaround while framework support is being added to
+ // clip non-square bitmaps into a perfect circle, manually crop the bitmap into
+ // into a square if it will be displayed as a thumbnail so that it can be cropped
+ // into a circle.
+ final int height = bitmap.getHeight();
+ final int width = bitmap.getWidth();
+
+ // The smaller dimension of a scaled bitmap can range from anywhere from 0 to just
+ // below twice the length of a thumbnail image due to the way we calculate the optimal
+ // sample size.
+ if (height != width && Math.min(height, width) <= mThumbnailSize * 2) {
+ final int dimension = Math.min(height, width);
+ bitmap = ThumbnailUtils.extractThumbnail(bitmap, dimension, dimension);
+ }
+ // make bitmap mutable and draw size onto it
+ if (DEBUG_SIZES) {
+ Bitmap original = bitmap;
+ bitmap = bitmap.copy(bitmap.getConfig(), true);
+ original.recycle();
+ Canvas canvas = new Canvas(bitmap);
+ Paint paint = new Paint();
+ paint.setTextSize(16);
+ paint.setColor(Color.BLUE);
+ paint.setStyle(Style.FILL);
+ canvas.drawRect(0.0f, 0.0f, 50.0f, 20.0f, paint);
+ paint.setColor(Color.WHITE);
+ paint.setAntiAlias(true);
+ canvas.drawText(bitmap.getWidth() + "/" + sampleSize, 0, 15, paint);
+ }
+
+ holder.decodedSampleSize = sampleSize;
+ holder.bitmap = bitmap;
+ holder.bitmapRef = new SoftReference<Bitmap>(bitmap);
+ if (DEBUG) {
+ Log.d(TAG, "inflateBitmap " + btk(bytes.length) + " -> "
+ + bitmap.getWidth() + "x" + bitmap.getHeight()
+ + ", " + btk(bitmap.getByteCount()));
+ }
+ } catch (OutOfMemoryError e) {
+ // Do nothing - the photo will appear to be missing
+ }
+ }
+
+ public void clear() {
+ if (DEBUG) Log.d(TAG, "clear");
+ mPendingRequests.clear();
+ mBitmapHolderCache.evictAll();
+ mBitmapCache.evictAll();
+ }
+
+ @Override
+ public void pause() {
+ mPaused = true;
+ }
+
+ @Override
+ public void resume() {
+ mPaused = false;
+ if (DEBUG) dumpStats();
+ if (!mPendingRequests.isEmpty()) {
+ requestLoading();
+ }
+ }
+
+ /**
+ * Sends a message to this thread itself to start loading images. If the current
+ * view contains multiple image views, all of those image views will get a chance
+ * to request their respective photos before any of those requests are executed.
+ * This allows us to load images in bulk.
+ */
+ private void requestLoading() {
+ if (!mLoadingRequested) {
+ mLoadingRequested = true;
+ mMainThreadHandler.sendEmptyMessage(MESSAGE_REQUEST_LOADING);
+ }
+ }
+
+ /**
+ * Processes requests on the main thread.
+ */
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_REQUEST_LOADING: {
+ mLoadingRequested = false;
+ if (!mPaused) {
+ ensureLoaderThread();
+ mLoaderThread.requestLoading();
+ }
+ return true;
+ }
+
+ case MESSAGE_PHOTOS_LOADED: {
+ if (!mPaused) {
+ processLoadedImages();
+ }
+ if (DEBUG) dumpStats();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void ensureLoaderThread() {
+ if (mLoaderThread == null) {
+ mLoaderThread = new LoaderThread(mContext.getContentResolver());
+ mLoaderThread.start();
+ }
+ }
+
+ /**
+ * Goes over pending loading requests and displays loaded photos. If some of the
+ * photos still haven't been loaded, sends another request for image loading.
+ */
+ private void processLoadedImages() {
+ final Iterator<Entry<ImageView, Request>> iterator = mPendingRequests.entrySet().iterator();
+ while (iterator.hasNext()) {
+ final Entry<ImageView, Request> entry = iterator.next();
+ // TODO: Temporarily disable contact photo fading in, until issues with
+ // RoundedBitmapDrawables overlapping the default image drawables are resolved.
+ final boolean loaded = loadCachedPhoto(entry.getKey(), entry.getValue(), false);
+ if (loaded) {
+ iterator.remove();
+ }
+ }
+
+ softenCache();
+
+ if (!mPendingRequests.isEmpty()) {
+ requestLoading();
+ }
+ }
+
+ /**
+ * Removes strong references to loaded bitmaps to allow them to be garbage collected
+ * if needed. Some of the bitmaps will still be retained by {@link #mBitmapCache}.
+ */
+ private void softenCache() {
+ for (BitmapHolder holder : mBitmapHolderCache.snapshot().values()) {
+ holder.bitmap = null;
+ }
+ }
+
+ /**
+ * Stores the supplied bitmap in cache.
+ */
+ private void cacheBitmap(Object key, byte[] bytes, boolean preloading, int requestedExtent) {
+ if (DEBUG) {
+ BitmapHolder prev = mBitmapHolderCache.get(key);
+ if (prev != null && prev.bytes != null) {
+ Log.d(TAG, "Overwriting cache: key=" + key + (prev.fresh ? " FRESH" : " stale"));
+ if (prev.fresh) {
+ mFreshCacheOverwrite.incrementAndGet();
+ } else {
+ mStaleCacheOverwrite.incrementAndGet();
+ }
+ }
+ Log.d(TAG, "Caching data: key=" + key + ", " +
+ (bytes == null ? "<null>" : btk(bytes.length)));
+ }
+ BitmapHolder holder = new BitmapHolder(bytes,
+ bytes == null ? -1 : BitmapUtil.getSmallerExtentFromBytes(bytes));
+
+ // Unless this image is being preloaded, decode it right away while
+ // we are still on the background thread.
+ if (!preloading) {
+ inflateBitmap(holder, requestedExtent);
+ }
+
+ if (bytes != null) {
+ mBitmapHolderCache.put(key, holder);
+ if (mBitmapHolderCache.get(key) != holder) {
+ Log.w(TAG, "Bitmap too big to fit in cache.");
+ mBitmapHolderCache.put(key, BITMAP_UNAVAILABLE);
+ }
+ } else {
+ mBitmapHolderCache.put(key, BITMAP_UNAVAILABLE);
+ }
+
+ mBitmapHolderCacheAllUnfresh = false;
+ }
+
+ @Override
+ public void cacheBitmap(Uri photoUri, Bitmap bitmap, byte[] photoBytes) {
+ final int smallerExtent = Math.min(bitmap.getWidth(), bitmap.getHeight());
+ // We can pretend here that the extent of the photo was the size that we originally
+ // requested
+ Request request = Request.createFromUri(photoUri, smallerExtent, false /* darkTheme */,
+ false /* isCircular */ , DEFAULT_AVATAR);
+ BitmapHolder holder = new BitmapHolder(photoBytes, smallerExtent);
+ holder.bitmapRef = new SoftReference<Bitmap>(bitmap);
+ mBitmapHolderCache.put(request.getKey(), holder);
+ mBitmapHolderCacheAllUnfresh = false;
+ mBitmapCache.put(request.getKey(), bitmap);
+ }
+
+ /**
+ * Populates an array of photo IDs that need to be loaded. Also decodes bitmaps that we have
+ * already loaded
+ */
+ private void obtainPhotoIdsAndUrisToLoad(Set<Long> photoIds,
+ Set<String> photoIdsAsStrings, Set<Request> uris) {
+ photoIds.clear();
+ photoIdsAsStrings.clear();
+ uris.clear();
+
+ boolean jpegsDecoded = false;
+
+ /*
+ * Since the call is made from the loader thread, the map could be
+ * changing during the iteration. That's not really a problem:
+ * ConcurrentHashMap will allow those changes to happen without throwing
+ * exceptions. Since we may miss some requests in the situation of
+ * concurrent change, we will need to check the map again once loading
+ * is complete.
+ */
+ Iterator<Request> iterator = mPendingRequests.values().iterator();
+ while (iterator.hasNext()) {
+ Request request = iterator.next();
+ final BitmapHolder holder = mBitmapHolderCache.get(request.getKey());
+ if (holder == BITMAP_UNAVAILABLE) {
+ continue;
+ }
+ if (holder != null && holder.bytes != null && holder.fresh &&
+ (holder.bitmapRef == null || holder.bitmapRef.get() == null)) {
+ // This was previously loaded but we don't currently have the inflated Bitmap
+ inflateBitmap(holder, request.getRequestedExtent());
+ jpegsDecoded = true;
+ } else {
+ if (holder == null || !holder.fresh) {
+ if (request.isUriRequest()) {
+ uris.add(request);
+ } else {
+ photoIds.add(request.getId());
+ photoIdsAsStrings.add(String.valueOf(request.mId));
+ }
+ }
+ }
+ }
+
+ if (jpegsDecoded) mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
+ }
+
+ /**
+ * The thread that performs loading of photos from the database.
+ */
+ private class LoaderThread extends HandlerThread implements Callback {
+ private static final int BUFFER_SIZE = 1024*16;
+ private static final int MESSAGE_PRELOAD_PHOTOS = 0;
+ private static final int MESSAGE_LOAD_PHOTOS = 1;
+
+ /**
+ * A pause between preload batches that yields to the UI thread.
+ */
+ private static final int PHOTO_PRELOAD_DELAY = 1000;
+
+ /**
+ * Number of photos to preload per batch.
+ */
+ private static final int PRELOAD_BATCH = 25;
+
+ /**
+ * Maximum number of photos to preload. If the cache size is 2Mb and
+ * the expected average size of a photo is 4kb, then this number should be 2Mb/4kb = 500.
+ */
+ private static final int MAX_PHOTOS_TO_PRELOAD = 100;
+
+ private final ContentResolver mResolver;
+ private final StringBuilder mStringBuilder = new StringBuilder();
+ private final Set<Long> mPhotoIds = Sets.newHashSet();
+ private final Set<String> mPhotoIdsAsStrings = Sets.newHashSet();
+ private final Set<Request> mPhotoUris = Sets.newHashSet();
+ private final List<Long> mPreloadPhotoIds = Lists.newArrayList();
+
+ private Handler mLoaderThreadHandler;
+ private byte mBuffer[];
+
+ private static final int PRELOAD_STATUS_NOT_STARTED = 0;
+ private static final int PRELOAD_STATUS_IN_PROGRESS = 1;
+ private static final int PRELOAD_STATUS_DONE = 2;
+
+ private int mPreloadStatus = PRELOAD_STATUS_NOT_STARTED;
+
+ public LoaderThread(ContentResolver resolver) {
+ super(LOADER_THREAD_NAME);
+ mResolver = resolver;
+ }
+
+ public void ensureHandler() {
+ if (mLoaderThreadHandler == null) {
+ mLoaderThreadHandler = new Handler(getLooper(), this);
+ }
+ }
+
+ /**
+ * Kicks off preloading of the next batch of photos on the background thread.
+ * Preloading will happen after a delay: we want to yield to the UI thread
+ * as much as possible.
+ * <p>
+ * If preloading is already complete, does nothing.
+ */
+ public void requestPreloading() {
+ if (mPreloadStatus == PRELOAD_STATUS_DONE) {
+ return;
+ }
+
+ ensureHandler();
+ if (mLoaderThreadHandler.hasMessages(MESSAGE_LOAD_PHOTOS)) {
+ return;
+ }
+
+ mLoaderThreadHandler.sendEmptyMessageDelayed(
+ MESSAGE_PRELOAD_PHOTOS, PHOTO_PRELOAD_DELAY);
+ }
+
+ /**
+ * Sends a message to this thread to load requested photos. Cancels a preloading
+ * request, if any: we don't want preloading to impede loading of the photos
+ * we need to display now.
+ */
+ public void requestLoading() {
+ ensureHandler();
+ mLoaderThreadHandler.removeMessages(MESSAGE_PRELOAD_PHOTOS);
+ mLoaderThreadHandler.sendEmptyMessage(MESSAGE_LOAD_PHOTOS);
+ }
+
+ /**
+ * Receives the above message, loads photos and then sends a message
+ * to the main thread to process them.
+ */
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_PRELOAD_PHOTOS:
+ preloadPhotosInBackground();
+ break;
+ case MESSAGE_LOAD_PHOTOS:
+ loadPhotosInBackground();
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * The first time it is called, figures out which photos need to be preloaded.
+ * Each subsequent call preloads the next batch of photos and requests
+ * another cycle of preloading after a delay. The whole process ends when
+ * we either run out of photos to preload or fill up cache.
+ */
+ private void preloadPhotosInBackground() {
+ if (mPreloadStatus == PRELOAD_STATUS_DONE) {
+ return;
+ }
+
+ if (mPreloadStatus == PRELOAD_STATUS_NOT_STARTED) {
+ queryPhotosForPreload();
+ if (mPreloadPhotoIds.isEmpty()) {
+ mPreloadStatus = PRELOAD_STATUS_DONE;
+ } else {
+ mPreloadStatus = PRELOAD_STATUS_IN_PROGRESS;
+ }
+ requestPreloading();
+ return;
+ }
+
+ if (mBitmapHolderCache.size() > mBitmapHolderCacheRedZoneBytes) {
+ mPreloadStatus = PRELOAD_STATUS_DONE;
+ return;
+ }
+
+ mPhotoIds.clear();
+ mPhotoIdsAsStrings.clear();
+
+ int count = 0;
+ int preloadSize = mPreloadPhotoIds.size();
+ while(preloadSize > 0 && mPhotoIds.size() < PRELOAD_BATCH) {
+ preloadSize--;
+ count++;
+ Long photoId = mPreloadPhotoIds.get(preloadSize);
+ mPhotoIds.add(photoId);
+ mPhotoIdsAsStrings.add(photoId.toString());
+ mPreloadPhotoIds.remove(preloadSize);
+ }
+
+ loadThumbnails(true);
+
+ if (preloadSize == 0) {
+ mPreloadStatus = PRELOAD_STATUS_DONE;
+ }
+
+ Log.v(TAG, "Preloaded " + count + " photos. Cached bytes: "
+ + mBitmapHolderCache.size());
+
+ requestPreloading();
+ }
+
+ private void queryPhotosForPreload() {
+ Cursor cursor = null;
+ try {
+ Uri uri = Contacts.CONTENT_URI.buildUpon().appendQueryParameter(
+ ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT))
+ .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(MAX_PHOTOS_TO_PRELOAD))
+ .build();
+ cursor = mResolver.query(uri, new String[] { Contacts.PHOTO_ID },
+ Contacts.PHOTO_ID + " NOT NULL AND " + Contacts.PHOTO_ID + "!=0",
+ null,
+ Contacts.STARRED + " DESC, " + Contacts.LAST_TIME_CONTACTED + " DESC");
+
+ if (cursor != null) {
+ while (cursor.moveToNext()) {
+ // Insert them in reverse order, because we will be taking
+ // them from the end of the list for loading.
+ mPreloadPhotoIds.add(0, cursor.getLong(0));
+ }
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ private void loadPhotosInBackground() {
+ if (!PermissionsUtil.hasPermission(mContext,
+ android.Manifest.permission.READ_CONTACTS)) {
+ return;
+ }
+ obtainPhotoIdsAndUrisToLoad(mPhotoIds, mPhotoIdsAsStrings, mPhotoUris);
+ loadThumbnails(false);
+ loadUriBasedPhotos();
+ requestPreloading();
+ }
+
+ /** Loads thumbnail photos with ids */
+ private void loadThumbnails(boolean preloading) {
+ if (mPhotoIds.isEmpty()) {
+ return;
+ }
+
+ // Remove loaded photos from the preload queue: we don't want
+ // the preloading process to load them again.
+ if (!preloading && mPreloadStatus == PRELOAD_STATUS_IN_PROGRESS) {
+ for (Long id : mPhotoIds) {
+ mPreloadPhotoIds.remove(id);
+ }
+ if (mPreloadPhotoIds.isEmpty()) {
+ mPreloadStatus = PRELOAD_STATUS_DONE;
+ }
+ }
+
+ mStringBuilder.setLength(0);
+ mStringBuilder.append(Photo._ID + " IN(");
+ for (int i = 0; i < mPhotoIds.size(); i++) {
+ if (i != 0) {
+ mStringBuilder.append(',');
+ }
+ mStringBuilder.append('?');
+ }
+ mStringBuilder.append(')');
+
+ Cursor cursor = null;
+ try {
+ if (DEBUG) Log.d(TAG, "Loading " + TextUtils.join(",", mPhotoIdsAsStrings));
+ cursor = mResolver.query(Data.CONTENT_URI,
+ COLUMNS,
+ mStringBuilder.toString(),
+ mPhotoIdsAsStrings.toArray(EMPTY_STRING_ARRAY),
+ null);
+
+ if (cursor != null) {
+ while (cursor.moveToNext()) {
+ Long id = cursor.getLong(0);
+ byte[] bytes = cursor.getBlob(1);
+ cacheBitmap(id, bytes, preloading, -1);
+ mPhotoIds.remove(id);
+ }
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ // Remaining photos were not found in the contacts database (but might be in profile).
+ for (Long id : mPhotoIds) {
+ if (ContactsContract.isProfileId(id)) {
+ Cursor profileCursor = null;
+ try {
+ profileCursor = mResolver.query(
+ ContentUris.withAppendedId(Data.CONTENT_URI, id),
+ COLUMNS, null, null, null);
+ if (profileCursor != null && profileCursor.moveToFirst()) {
+ cacheBitmap(profileCursor.getLong(0), profileCursor.getBlob(1),
+ preloading, -1);
+ } else {
+ // Couldn't load a photo this way either.
+ cacheBitmap(id, null, preloading, -1);
+ }
+ } finally {
+ if (profileCursor != null) {
+ profileCursor.close();
+ }
+ }
+ } else {
+ // Not a profile photo and not found - mark the cache accordingly
+ cacheBitmap(id, null, preloading, -1);
+ }
+ }
+
+ mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
+ }
+
+ /**
+ * Loads photos referenced with Uris. Those can be remote thumbnails
+ * (from directory searches), display photos etc
+ */
+ private void loadUriBasedPhotos() {
+ for (Request uriRequest : mPhotoUris) {
+ // Keep the original URI and use this to key into the cache. Failure to do so will
+ // result in an image being continually reloaded into cache if the original URI
+ // has a contact type encodedFragment (eg nearby places business photo URLs).
+ Uri originalUri = uriRequest.getUri();
+
+ // Strip off the "contact type" we added to the URI to ensure it was identifiable as
+ // a business photo -- there is no need to pass this on to the server.
+ Uri uri = ContactPhotoManager.removeContactType(originalUri);
+
+ if (mBuffer == null) {
+ mBuffer = new byte[BUFFER_SIZE];
+ }
+ try {
+ if (DEBUG) Log.d(TAG, "Loading " + uri);
+ final String scheme = uri.getScheme();
+ InputStream is = null;
+ if (scheme.equals("http") || scheme.equals("https")) {
+ TrafficStats.setThreadStatsTag(TrafficStatsTags.CONTACT_PHOTO_DOWNLOAD_TAG);
+ final HttpURLConnection connection =
+ (HttpURLConnection) new URL(uri.toString()).openConnection();
+
+ // Include the user agent if it is specified.
+ if (!TextUtils.isEmpty(mUserAgent)) {
+ connection.setRequestProperty("User-Agent", mUserAgent);
+ }
+ try {
+ is = connection.getInputStream();
+ } catch (IOException e) {
+ connection.disconnect();
+ is = null;
+ }
+ TrafficStats.clearThreadStatsTag();
+ } else {
+ is = mResolver.openInputStream(uri);
+ }
+ if (is != null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ int size;
+ while ((size = is.read(mBuffer)) != -1) {
+ baos.write(mBuffer, 0, size);
+ }
+ } finally {
+ is.close();
+ }
+ cacheBitmap(originalUri, baos.toByteArray(), false,
+ uriRequest.getRequestedExtent());
+ mMainThreadHandler.sendEmptyMessage(MESSAGE_PHOTOS_LOADED);
+ } else {
+ Log.v(TAG, "Cannot load photo " + uri);
+ cacheBitmap(originalUri, null, false, uriRequest.getRequestedExtent());
+ }
+ } catch (final Exception | OutOfMemoryError ex) {
+ Log.v(TAG, "Cannot load photo " + uri, ex);
+ cacheBitmap(originalUri, null, false, uriRequest.getRequestedExtent());
+ }
+ }
+ }
+ }
+
+ /**
+ * A holder for either a Uri or an id and a flag whether this was requested for the dark or
+ * light theme
+ */
+ private static final class Request {
+ private final long mId;
+ private final Uri mUri;
+ private final boolean mDarkTheme;
+ private final int mRequestedExtent;
+ private final DefaultImageProvider mDefaultProvider;
+ /**
+ * Whether or not the contact photo is to be displayed as a circle
+ */
+ private final boolean mIsCircular;
+
+ private Request(long id, Uri uri, int requestedExtent, boolean darkTheme,
+ boolean isCircular, DefaultImageProvider defaultProvider) {
+ mId = id;
+ mUri = uri;
+ mDarkTheme = darkTheme;
+ mIsCircular = isCircular;
+ mRequestedExtent = requestedExtent;
+ mDefaultProvider = defaultProvider;
+ }
+
+ public static Request createFromThumbnailId(long id, boolean darkTheme, boolean isCircular,
+ DefaultImageProvider defaultProvider) {
+ return new Request(id, null /* no URI */, -1, darkTheme, isCircular, defaultProvider);
+ }
+
+ public static Request createFromUri(Uri uri, int requestedExtent, boolean darkTheme,
+ boolean isCircular, DefaultImageProvider defaultProvider) {
+ return new Request(0 /* no ID */, uri, requestedExtent, darkTheme, isCircular,
+ defaultProvider);
+ }
+
+ public boolean isUriRequest() {
+ return mUri != null;
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ public long getId() {
+ return mId;
+ }
+
+ public int getRequestedExtent() {
+ return mRequestedExtent;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (int) (mId ^ (mId >>> 32));
+ result = prime * result + mRequestedExtent;
+ result = prime * result + ((mUri == null) ? 0 : mUri.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ final Request that = (Request) obj;
+ if (mId != that.mId) return false;
+ if (mRequestedExtent != that.mRequestedExtent) return false;
+ if (!UriUtils.areEqual(mUri, that.mUri)) return false;
+ // Don't compare equality of mDarkTheme because it is only used in the default contact
+ // photo case. When the contact does have a photo, the contact photo is the same
+ // regardless of mDarkTheme, so we shouldn't need to put the photo request on the queue
+ // twice.
+ return true;
+ }
+
+ public Object getKey() {
+ return mUri == null ? mId : mUri;
+ }
+
+ /**
+ * Applies the default image to the current view. If the request is URI-based, looks for
+ * the contact type encoded fragment to determine if this is a request for a business photo,
+ * in which case we will load the default business photo.
+ *
+ * @param view The current image view to apply the image to.
+ * @param isCircular Whether the image is circular or not.
+ */
+ public void applyDefaultImage(ImageView view, boolean isCircular) {
+ final DefaultImageRequest request;
+
+ if (isCircular) {
+ request = ContactPhotoManager.isBusinessContactUri(mUri)
+ ? DefaultImageRequest.EMPTY_CIRCULAR_BUSINESS_IMAGE_REQUEST
+ : DefaultImageRequest.EMPTY_CIRCULAR_DEFAULT_IMAGE_REQUEST;
+ } else {
+ request = ContactPhotoManager.isBusinessContactUri(mUri)
+ ? DefaultImageRequest.EMPTY_DEFAULT_BUSINESS_IMAGE_REQUEST
+ : DefaultImageRequest.EMPTY_DEFAULT_IMAGE_REQUEST;
+ }
+ mDefaultProvider.applyDefaultImage(view, mRequestedExtent, mDarkTheme, request);
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/ContactPresenceIconUtil.java b/src/com/android/contacts/common/ContactPresenceIconUtil.java
new file mode 100644
index 0000000..2f4c9ee
--- /dev/null
+++ b/src/com/android/contacts/common/ContactPresenceIconUtil.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 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.common;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.provider.ContactsContract.StatusUpdates;
+
+/**
+ * Define the contact present show policy in Contacts
+ */
+public class ContactPresenceIconUtil {
+ /**
+ * Get the presence icon resource according the status.
+ *
+ * @return null means don't show the status icon.
+ */
+ public static Drawable getPresenceIcon (Context context, int status) {
+ // We don't show the offline status in Contacts
+ switch(status) {
+ case StatusUpdates.AVAILABLE:
+ case StatusUpdates.IDLE:
+ case StatusUpdates.AWAY:
+ case StatusUpdates.DO_NOT_DISTURB:
+ case StatusUpdates.INVISIBLE:
+ return context.getResources().getDrawable(
+ StatusUpdates.getPresenceIconResourceId(status));
+ case StatusUpdates.OFFLINE:
+ // The undefined status is treated as OFFLINE in getPresenceIconResourceId();
+ default:
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/ContactStatusUtil.java b/src/com/android/contacts/common/ContactStatusUtil.java
new file mode 100644
index 0000000..a7d1925
--- /dev/null
+++ b/src/com/android/contacts/common/ContactStatusUtil.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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.common;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.ContactsContract.StatusUpdates;
+
+/**
+ * Provides static function to get default contact status message.
+ */
+public class ContactStatusUtil {
+
+ private static final String TAG = "ContactStatusUtil";
+
+ public static String getStatusString(Context context, int presence) {
+ Resources resources = context.getResources();
+ switch (presence) {
+ case StatusUpdates.AVAILABLE:
+ return resources.getString(R.string.status_available);
+ case StatusUpdates.IDLE:
+ case StatusUpdates.AWAY:
+ return resources.getString(R.string.status_away);
+ case StatusUpdates.DO_NOT_DISTURB:
+ return resources.getString(R.string.status_busy);
+ case StatusUpdates.OFFLINE:
+ case StatusUpdates.INVISIBLE:
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/src/com/android/contacts/common/ContactTileLoaderFactory.java b/src/com/android/contacts/common/ContactTileLoaderFactory.java
new file mode 100644
index 0000000..f75950e
--- /dev/null
+++ b/src/com/android/contacts/common/ContactTileLoaderFactory.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 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.common;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import android.content.Context;
+import android.content.CursorLoader;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts;
+
+/**
+ * Used to create {@link CursorLoader}s to load different groups of
+ * {@link com.android.contacts.list.ContactTileView}.
+ */
+public final class ContactTileLoaderFactory {
+
+ public final static int CONTACT_ID = 0;
+ public final static int DISPLAY_NAME = 1;
+ public final static int STARRED = 2;
+ public final static int PHOTO_URI = 3;
+ public final static int LOOKUP_KEY = 4;
+ public final static int CONTACT_PRESENCE = 5;
+ public final static int CONTACT_STATUS = 6;
+
+ // Only used for StrequentPhoneOnlyLoader
+ public final static int PHONE_NUMBER = 5;
+ public final static int PHONE_NUMBER_TYPE = 6;
+ public final static int PHONE_NUMBER_LABEL = 7;
+ public final static int IS_DEFAULT_NUMBER = 8;
+ public final static int PINNED = 9;
+ // The _ID field returned for strequent items actually contains data._id instead of
+ // contacts._id because the query is performed on the data table. In order to obtain the
+ // contact id for strequent items, we thus have to use Phone.contact_id instead.
+ public final static int CONTACT_ID_FOR_DATA = 10;
+ public final static int DISPLAY_NAME_ALTERNATIVE = 11;
+
+ private static final String[] COLUMNS = new String[] {
+ Contacts._ID, // ..........................................0
+ Contacts.DISPLAY_NAME, // .................................1
+ Contacts.STARRED, // ......................................2
+ Contacts.PHOTO_URI, // ....................................3
+ Contacts.LOOKUP_KEY, // ...................................4
+ Contacts.CONTACT_PRESENCE, // .............................5
+ Contacts.CONTACT_STATUS, // ...............................6
+ };
+
+ /**
+ * Projection used for the {@link Contacts#CONTENT_STREQUENT_URI}
+ * query when {@link ContactsContract#STREQUENT_PHONE_ONLY} flag
+ * is set to true. The main difference is the lack of presence
+ * and status data and the addition of phone number and label.
+ */
+ @VisibleForTesting
+ public static final String[] COLUMNS_PHONE_ONLY = new String[] {
+ Contacts._ID, // ..........................................0
+ Contacts.DISPLAY_NAME_PRIMARY, // .........................1
+ Contacts.STARRED, // ......................................2
+ Contacts.PHOTO_URI, // ....................................3
+ Contacts.LOOKUP_KEY, // ...................................4
+ Phone.NUMBER, // ..........................................5
+ Phone.TYPE, // ............................................6
+ Phone.LABEL, // ...........................................7
+ Phone.IS_SUPER_PRIMARY, //.................................8
+ Contacts.PINNED, // .......................................9
+ Phone.CONTACT_ID, //.......................................10
+ Contacts.DISPLAY_NAME_ALTERNATIVE, // .....................11
+ };
+
+ private static final String STARRED_ORDER = Contacts.DISPLAY_NAME+" COLLATE NOCASE ASC";
+
+ public static CursorLoader createStrequentLoader(Context context) {
+ return new CursorLoader(context, Contacts.CONTENT_STREQUENT_URI, COLUMNS, null, null,
+ STARRED_ORDER);
+ }
+
+ public static CursorLoader createStrequentPhoneOnlyLoader(Context context) {
+ Uri uri = Contacts.CONTENT_STREQUENT_URI.buildUpon()
+ .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true").build();
+
+ return new CursorLoader(context, uri, COLUMNS_PHONE_ONLY, null, null, null);
+ }
+
+ public static CursorLoader createStarredLoader(Context context) {
+ return new CursorLoader(context, Contacts.CONTENT_URI, COLUMNS, Contacts.STARRED + "=?",
+ new String[]{"1"}, STARRED_ORDER);
+ }
+
+ public static CursorLoader createFrequentLoader(Context context) {
+ return new CursorLoader(context, Contacts.CONTENT_FREQUENT_URI, COLUMNS,
+ Contacts.STARRED + "=?", new String[]{"0"}, null);
+ }
+}
diff --git a/src/com/android/contacts/common/ContactsUtils.java b/src/com/android/contacts/common/ContactsUtils.java
new file mode 100644
index 0000000..38fdbf2
--- /dev/null
+++ b/src/com/android/contacts/common/ContactsUtils.java
@@ -0,0 +1,280 @@
+/*
+ * 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.common;
+
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.support.annotation.IntDef;
+import android.provider.ContactsContract.DisplayPhoto;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.dataitem.ImDataItem;
+import com.android.contacts.common.testing.NeededForTesting;
+import com.android.contacts.common.compat.ContactsCompat;
+import com.android.contacts.common.compat.DirectoryCompat;
+import com.android.contacts.common.model.AccountTypeManager;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+public class ContactsUtils {
+ private static final String TAG = "ContactsUtils";
+
+ // Telecomm related schemes are in CallUtil
+ public static final String SCHEME_IMTO = "imto";
+ public static final String SCHEME_MAILTO = "mailto";
+ public static final String SCHEME_SMSTO = "smsto";
+
+ private static final int DEFAULT_THUMBNAIL_SIZE = 96;
+
+ private static int sThumbnailSize = -1;
+
+ public static final boolean FLAG_N_FEATURE = Build.VERSION.SDK_INT >= 24;
+
+ // TODO find a proper place for the canonical version of these
+ public interface ProviderNames {
+ String YAHOO = "Yahoo";
+ String GTALK = "GTalk";
+ String MSN = "MSN";
+ String ICQ = "ICQ";
+ String AIM = "AIM";
+ String XMPP = "XMPP";
+ String JABBER = "JABBER";
+ String SKYPE = "SKYPE";
+ String QQ = "QQ";
+ }
+
+ /**
+ * This looks up the provider name defined in
+ * 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;
+ }
+
+
+ public static final long USER_TYPE_CURRENT = 0;
+ public static final long USER_TYPE_WORK = 1;
+
+ /**
+ * UserType indicates the user type of the contact. If the contact is from Work User (Work
+ * Profile in Android Multi-User System), it's {@link #USER_TYPE_WORK}, otherwise,
+ * {@link #USER_TYPE_CURRENT}. Please note that current user can be in work profile, where the
+ * dialer is running inside Work Profile.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({USER_TYPE_CURRENT, USER_TYPE_WORK})
+ public @interface UserType {}
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Returns true if two objects are considered equal. Two null references are equal here.
+ */
+ @NeededForTesting
+ public static boolean areObjectsEqual(Object a, Object b) {
+ return a == b || (a != null && a.equals(b));
+ }
+
+ /**
+ * Returns true if two {@link Intent}s are both null, or have the same action.
+ */
+ public static final boolean areIntentActionEqual(Intent a, Intent b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ return TextUtils.equals(a.getAction(), b.getAction());
+ }
+
+ public static boolean areGroupWritableAccountsAvailable(Context context) {
+ final List<AccountWithDataSet> accounts =
+ AccountTypeManager.getInstance(context).getGroupWritableAccounts();
+ return !accounts.isEmpty();
+ }
+
+ /**
+ * Returns the size (width and height) of thumbnail pictures as configured in the provider. This
+ * can safely be called from the UI thread, as the provider can serve this without performing
+ * a database access
+ */
+ public static int getThumbnailSize(Context context) {
+ if (sThumbnailSize == -1) {
+ final Cursor c = context.getContentResolver().query(
+ DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
+ new String[] { DisplayPhoto.THUMBNAIL_MAX_DIM }, null, null, null);
+ if (c != null) {
+ try {
+ if (c.moveToFirst()) {
+ sThumbnailSize = c.getInt(0);
+ }
+ } finally {
+ c.close();
+ }
+ }
+ }
+ return sThumbnailSize != -1 ? sThumbnailSize : DEFAULT_THUMBNAIL_SIZE;
+ }
+
+ private static Intent getCustomImIntent(ImDataItem im, int protocol) {
+ String host = im.getCustomProtocol();
+ final String data = im.getData();
+ if (TextUtils.isEmpty(data)) {
+ return null;
+ }
+ if (protocol != Im.PROTOCOL_CUSTOM) {
+ // Try bringing in a well-known host for specific protocols
+ host = ContactsUtils.lookupProviderNameFromId(protocol);
+ }
+ if (TextUtils.isEmpty(host)) {
+ return null;
+ }
+ final String authority = host.toLowerCase();
+ final Uri imUri = new Uri.Builder().scheme(SCHEME_IMTO).authority(
+ authority).appendPath(data).build();
+ final Intent intent = new Intent(Intent.ACTION_SENDTO, imUri);
+ return intent;
+ }
+
+ /**
+ * Returns the proper Intent for an ImDatItem. If available, a secondary intent is stored
+ * in the second Pair slot
+ */
+ public static Pair<Intent, Intent> buildImIntent(Context context, ImDataItem im) {
+ Intent intent = null;
+ Intent secondaryIntent = null;
+ final boolean isEmail = im.isCreatedFromEmail();
+
+ if (!isEmail && !im.isProtocolValid()) {
+ return new Pair<>(null, null);
+ }
+
+ final String data = im.getData();
+ if (TextUtils.isEmpty(data)) {
+ return new Pair<>(null, null);
+ }
+
+ final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : im.getProtocol();
+
+ if (protocol == Im.PROTOCOL_GOOGLE_TALK) {
+ final int chatCapability = im.getChatCapability();
+ if ((chatCapability & Im.CAPABILITY_HAS_CAMERA) != 0) {
+ intent = new Intent(Intent.ACTION_SENDTO,
+ Uri.parse("xmpp:" + data + "?message"));
+ secondaryIntent = new Intent(Intent.ACTION_SENDTO,
+ Uri.parse("xmpp:" + data + "?call"));
+ } else if ((chatCapability & Im.CAPABILITY_HAS_VOICE) != 0) {
+ // Allow Talking and Texting
+ intent =
+ new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?message"));
+ secondaryIntent =
+ new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?call"));
+ } else {
+ intent =
+ new Intent(Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?message"));
+ }
+ } else {
+ // Build an IM Intent
+ intent = getCustomImIntent(im, protocol);
+ }
+ return new Pair<>(intent, secondaryIntent);
+ }
+
+ /**
+ * Determine UserType from directory id and contact id.
+ *
+ * 3 types of query
+ *
+ * 1. 2 profile query: content://com.android.contacts/phone_lookup_enterprise/1234567890
+ * personal and work contact are mixed into one cursor. no directory id. contact_id indicates if
+ * it's work contact
+ *
+ * 2. work local query:
+ * content://com.android.contacts/phone_lookup_enterprise/1234567890?directory=1000000000
+ * either directory_id or contact_id is enough to identify work contact
+ *
+ * 3. work remote query:
+ * content://com.android.contacts/phone_lookup_enterprise/1234567890?directory=1000000003
+ * contact_id is random. only directory_id is available
+ *
+ * Summary: If directory_id is not null, always use directory_id to identify work contact.
+ * (which is the case here) Otherwise, use contact_id.
+ *
+ * @param directoryId directory id of ContactsProvider query
+ * @param contactId contact id
+ * @return UserType indicates the user type of the contact. A directory id or contact id larger
+ * than a thredshold indicates that the contact is stored in Work Profile, but not in
+ * current user. It's a contract by ContactsProvider and check by
+ * Contacts.isEnterpriseDirectoryId and Contacts.isEnterpriseContactId. Currently, only
+ * 2 kinds of users can be detected from the directoryId and contactId as
+ * ContactsProvider can only access current and work user's contacts
+ */
+ public static @UserType long determineUserType(Long directoryId, Long contactId) {
+ // First check directory id
+ if (directoryId != null) {
+ return DirectoryCompat.isEnterpriseDirectoryId(directoryId) ? USER_TYPE_WORK
+ : USER_TYPE_CURRENT;
+ }
+ // Only check contact id if directory id is null
+ if (contactId != null && contactId != 0L
+ && ContactsCompat.isEnterpriseContactId(contactId)) {
+ return USER_TYPE_WORK;
+ } else {
+ return USER_TYPE_CURRENT;
+ }
+
+ }
+}
diff --git a/src/com/android/contacts/common/Experiments.java b/src/com/android/contacts/common/Experiments.java
new file mode 100644
index 0000000..c811e27
--- /dev/null
+++ b/src/com/android/contacts/common/Experiments.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 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.common;
+
+/**
+ * Experiment flag names.
+ */
+public final class Experiments {
+
+ private Experiments() {
+ }
+}
diff --git a/src/com/android/contacts/common/GeoUtil.java b/src/com/android/contacts/common/GeoUtil.java
new file mode 100644
index 0000000..cd0139b
--- /dev/null
+++ b/src/com/android/contacts/common/GeoUtil.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012 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.common;
+
+import android.app.Application;
+import android.content.Context;
+
+import com.android.contacts.common.location.CountryDetector;
+
+import com.google.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder;
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.Phonenumber;
+
+import java.util.Locale;
+
+/**
+ * Static methods related to Geo.
+ */
+public class GeoUtil {
+
+ /**
+ * Returns the country code of the country the user is currently in. Before calling this
+ * method, make sure that {@link CountryDetector#initialize(Context)} has already been called
+ * in {@link Application#onCreate()}.
+ * @return The ISO 3166-1 two letters country code of the country the user
+ * is in.
+ */
+ public static String getCurrentCountryIso(Context context) {
+ // The {@link CountryDetector} should never return null so this is safe to return as-is.
+ return CountryDetector.getInstance(context).getCurrentCountryIso();
+ }
+
+ public static String getGeocodedLocationFor(Context context, String phoneNumber) {
+ final PhoneNumberOfflineGeocoder geocoder = PhoneNumberOfflineGeocoder.getInstance();
+ final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
+ try {
+ final Phonenumber.PhoneNumber structuredPhoneNumber =
+ phoneNumberUtil.parse(phoneNumber, getCurrentCountryIso(context));
+ final Locale locale = context.getResources().getConfiguration().locale;
+ return geocoder.getDescriptionForNumber(structuredPhoneNumber, locale);
+ } catch (NumberParseException e) {
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/GroupMetaData.java b/src/com/android/contacts/common/GroupMetaData.java
new file mode 100644
index 0000000..fa86ae2
--- /dev/null
+++ b/src/com/android/contacts/common/GroupMetaData.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 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.common;
+
+/**
+ * Meta-data for a contact group. We load all groups associated with the contact's
+ * constituent accounts.
+ */
+public final class GroupMetaData {
+ private String mAccountName;
+ private String mAccountType;
+ private String mDataSet;
+ private long mGroupId;
+ private String mTitle;
+ private boolean mDefaultGroup;
+ private boolean mFavorites;
+
+ public GroupMetaData(String accountName, String accountType, String dataSet, long groupId,
+ String title, boolean defaultGroup, boolean favorites) {
+ this.mAccountName = accountName;
+ this.mAccountType = accountType;
+ this.mDataSet = dataSet;
+ this.mGroupId = groupId;
+ this.mTitle = title;
+ this.mDefaultGroup = defaultGroup;
+ this.mFavorites = favorites;
+ }
+
+ public String getAccountName() {
+ return mAccountName;
+ }
+
+ public String getAccountType() {
+ return mAccountType;
+ }
+
+ public String getDataSet() {
+ return mDataSet;
+ }
+
+ public long getGroupId() {
+ return mGroupId;
+ }
+
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public boolean isDefaultGroup() {
+ return mDefaultGroup;
+ }
+
+ public boolean isFavorites() {
+ return mFavorites;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/common/MoreContactUtils.java b/src/com/android/contacts/common/MoreContactUtils.java
new file mode 100644
index 0000000..9b9f800
--- /dev/null
+++ b/src/com/android/contacts/common/MoreContactUtils.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2012 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.common;
+
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.contacts.common.model.account.AccountType;
+
+/**
+ * Shared static contact utility methods.
+ */
+public class MoreContactUtils {
+
+ private static final String WAIT_SYMBOL_AS_STRING = String.valueOf(PhoneNumberUtils.WAIT);
+
+ /**
+ * Returns true if two data with mimetypes which represent values in contact entries are
+ * considered equal for collapsing in the GUI. For caller-id, use
+ * {@link android.telephony.PhoneNumberUtils#compare(android.content.Context, String, String)}
+ * instead
+ */
+ public static boolean shouldCollapse(CharSequence mimetype1, CharSequence data1,
+ CharSequence mimetype2, CharSequence data2) {
+ // different mimetypes? don't collapse
+ if (!TextUtils.equals(mimetype1, mimetype2)) return false;
+
+ // exact same string? good, bail out early
+ if (TextUtils.equals(data1, data2)) return true;
+
+ // so if either is null, these two must be different
+ if (data1 == null || data2 == null) return false;
+
+ // if this is not about phone numbers, we know this is not a match (of course, some
+ // mimetypes could have more sophisticated matching is the future, e.g. addresses)
+ if (!TextUtils.equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
+ mimetype1)) {
+ return false;
+ }
+
+ return shouldCollapsePhoneNumbers(data1.toString(), data2.toString());
+ }
+
+ // TODO: Move this to PhoneDataItem.shouldCollapse override
+ private static boolean shouldCollapsePhoneNumbers(String number1, String number2) {
+ // Work around to address b/20724444. We want to distinguish between #555, *555 and 555.
+ // This makes no attempt to distinguish between 555 and 55*5, since 55*5 is an improbable
+ // number. PhoneNumberUtil already distinguishes between 555 and 55#5.
+ if (number1.contains("#") != number2.contains("#")
+ || number1.contains("*") != number2.contains("*")) {
+ return false;
+ }
+
+ // Now do the full phone number thing. split into parts, separated by waiting symbol
+ // and compare them individually
+ final String[] dataParts1 = number1.split(WAIT_SYMBOL_AS_STRING);
+ final String[] dataParts2 = number2.split(WAIT_SYMBOL_AS_STRING);
+ if (dataParts1.length != dataParts2.length) return false;
+ final PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+ for (int i = 0; i < dataParts1.length; i++) {
+ // Match phone numbers represented by keypad letters, in which case prefer the
+ // phone number with letters.
+ final String dataPart1 = PhoneNumberUtils.convertKeypadLettersToDigits(dataParts1[i]);
+ final String dataPart2 = dataParts2[i];
+
+ // substrings equal? shortcut, don't parse
+ if (TextUtils.equals(dataPart1, dataPart2)) continue;
+
+ // do a full parse of the numbers
+ final PhoneNumberUtil.MatchType result = util.isNumberMatch(dataPart1, dataPart2);
+ switch (result) {
+ case NOT_A_NUMBER:
+ // don't understand the numbers? let's play it safe
+ return false;
+ case NO_MATCH:
+ return false;
+ case EXACT_MATCH:
+ break;
+ case NSN_MATCH:
+ try {
+ // For NANP phone numbers, match when one has +1 and the other does not.
+ // In this case, prefer the +1 version.
+ if (util.parse(dataPart1, null).getCountryCode() == 1) {
+ // At this point, the numbers can be either case 1 or 2 below....
+ //
+ // case 1)
+ // +14155551212 <--- country code 1
+ // 14155551212 <--- 1 is trunk prefix, not country code
+ //
+ // and
+ //
+ // case 2)
+ // +14155551212
+ // 4155551212
+ //
+ // From b/7519057, case 2 needs to be equal. But also that bug, case 3
+ // below should not be equal.
+ //
+ // case 3)
+ // 14155551212
+ // 4155551212
+ //
+ // So in order to make sure transitive equality is valid, case 1 cannot
+ // be equal. Otherwise, transitive equality breaks and the following
+ // would all be collapsed:
+ // 4155551212 |
+ // 14155551212 |----> +14155551212
+ // +14155551212 |
+ //
+ // With transitive equality, the collapsed values should be:
+ // 4155551212 | 14155551212
+ // 14155551212 |----> +14155551212
+ // +14155551212 |
+
+ // Distinguish between case 1 and 2 by checking for trunk prefix '1'
+ // at the start of number 2.
+ if (dataPart2.trim().charAt(0) == '1') {
+ // case 1
+ return false;
+ }
+ break;
+ }
+ } catch (NumberParseException e) {
+ // This is the case where the first number does not have a country code.
+ // examples:
+ // (123) 456-7890 & 123-456-7890 (collapse)
+ // 0049 (8092) 1234 & +49/80921234 (unit test says do not collapse)
+
+ // Check the second number. If it also does not have a country code, then
+ // we should collapse. If it has a country code, then it's a different
+ // number and we should not collapse (this conclusion is based on an
+ // existing unit test).
+ try {
+ util.parse(dataPart2, null);
+ } catch (NumberParseException e2) {
+ // Number 2 also does not have a country. Collapse.
+ break;
+ }
+ }
+ return false;
+ case SHORT_NSN_MATCH:
+ return false;
+ default:
+ throw new IllegalStateException("Unknown result value from phone number " +
+ "library");
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the {@link android.graphics.Rect} with left, top, right, and bottom coordinates
+ * that are equivalent to the given {@link android.view.View}'s bounds. This is equivalent to
+ * how the target {@link android.graphics.Rect} is calculated in
+ * {@link android.provider.ContactsContract.QuickContact#showQuickContact}.
+ */
+ public static Rect getTargetRectFromView(View view) {
+ final int[] pos = new int[2];
+ view.getLocationOnScreen(pos);
+
+ final Rect rect = new Rect();
+ rect.left = pos[0];
+ rect.top = pos[1];
+ rect.right = pos[0] + view.getWidth();
+ rect.bottom = pos[1] + view.getHeight();
+ return rect;
+ }
+
+ /**
+ * Returns a header view based on the R.layout.list_separator, where the
+ * containing {@link android.widget.TextView} is set using the given textResourceId.
+ */
+ public static TextView createHeaderView(Context context, int textResourceId) {
+ final TextView textView = (TextView) View.inflate(context, R.layout.list_separator, null);
+ textView.setText(context.getString(textResourceId));
+ return textView;
+ }
+
+ /**
+ * Set the top padding on the header view dynamically, based on whether the header is in
+ * the first row or not.
+ */
+ public static void setHeaderViewBottomPadding(Context context, TextView textView,
+ boolean isFirstRow) {
+ final int topPadding;
+ if (isFirstRow) {
+ topPadding = (int) context.getResources().getDimension(
+ R.dimen.frequently_contacted_title_top_margin_when_first_row);
+ } else {
+ topPadding = (int) context.getResources().getDimension(
+ R.dimen.frequently_contacted_title_top_margin);
+ }
+ textView.setPaddingRelative(textView.getPaddingStart(), topPadding,
+ textView.getPaddingEnd(), textView.getPaddingBottom());
+ }
+
+
+ /**
+ * Returns the intent to launch for the given invitable account type and contact lookup URI.
+ * This will return null if the account type is not invitable (i.e. there is no
+ * {@link AccountType#getInviteContactActivityClassName()} or
+ * {@link AccountType#syncAdapterPackageName}).
+ */
+ public static Intent getInvitableIntent(AccountType accountType, Uri lookupUri) {
+ String syncAdapterPackageName = accountType.syncAdapterPackageName;
+ String className = accountType.getInviteContactActivityClassName();
+ if (TextUtils.isEmpty(syncAdapterPackageName) || TextUtils.isEmpty(className)) {
+ return null;
+ }
+ Intent intent = new Intent();
+ intent.setClassName(syncAdapterPackageName, className);
+
+ intent.setAction(ContactsContract.Intents.INVITE_CONTACT);
+
+ // Data is the lookup URI.
+ intent.setData(lookupUri);
+ return intent;
+ }
+}
diff --git a/src/com/android/contacts/common/activity/AppCompatTransactionSafeActivity.java b/src/com/android/contacts/common/activity/AppCompatTransactionSafeActivity.java
new file mode 100644
index 0000000..e70a9fd
--- /dev/null
+++ b/src/com/android/contacts/common/activity/AppCompatTransactionSafeActivity.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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.common.activity;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+/**
+ * A common superclass that keeps track of whether an {@link AppCompatActivity} has saved its state
+ * yet or not, copied from {@link com.android.contacts.common.activity.TransactionSafeActivity},
+ * which will be deprecated after Kitkat backporting is done.
+ */
+public abstract class AppCompatTransactionSafeActivity extends AppCompatActivity {
+
+ private boolean mIsSafeToCommitTransactions;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mIsSafeToCommitTransactions = true;
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mIsSafeToCommitTransactions = true;
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mIsSafeToCommitTransactions = true;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mIsSafeToCommitTransactions = false;
+ }
+
+ /**
+ * Returns true if it is safe to commit {@link FragmentTransaction}s at this time, based on
+ * whether {@link FragmentActivity#onSaveInstanceState} has been called or not.
+ *
+ * Make sure that the current activity calls into
+ * {@link super.onSaveInstanceState(Bundle outState)} (if that method is overridden),
+ * so the flag is properly set.
+ */
+ public boolean isSafeToCommitTransactions() {
+ return mIsSafeToCommitTransactions;
+ }
+}
diff --git a/src/com/android/contacts/common/activity/LicenseActivity.java b/src/com/android/contacts/common/activity/LicenseActivity.java
new file mode 100644
index 0000000..71bcd84
--- /dev/null
+++ b/src/com/android/contacts/common/activity/LicenseActivity.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 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.common.activity;
+
+import com.android.contacts.common.R;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.webkit.WebView;
+
+/**
+ * Displays the licenses for all open source libraries.
+ */
+public class LicenseActivity extends Activity {
+ private static final String LICENSE_FILE = "file:///android_asset/licenses.html";
+ private WebView mWebView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.licenses);
+ mWebView = (WebView) findViewById(R.id.webview);
+ mWebView.loadUrl(LICENSE_FILE);
+ final ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ mWebView.destroy();
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/src/com/android/contacts/common/activity/RequestDesiredPermissionsActivity.java b/src/com/android/contacts/common/activity/RequestDesiredPermissionsActivity.java
new file mode 100644
index 0000000..8098fdf
--- /dev/null
+++ b/src/com/android/contacts/common/activity/RequestDesiredPermissionsActivity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 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.common.activity;
+
+import android.Manifest.permission;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Requests permissions that are not absolutely required by the calling Activity;
+ * if permissions are denied, the calling Activity is still restarted.
+ *
+ * Activities that have a set of permissions that must be granted in order for the Activity to
+ * function propertly should call
+ * {@link RequestPermissionsActivity#startPermissionActivity(Activity, String[], Class)}
+ * before calling {@link RequestDesiredPermissionsActivity#startPermissionActivity(Activity)}.
+ */
+public class RequestDesiredPermissionsActivity extends RequestPermissionsActivityBase {
+
+ private static String[] sDesiredPermissions;
+
+ @Override
+ protected String[] getPermissions() {
+ return getPermissions(getPackageManager());
+ }
+
+ /**
+ * If any desired permission that Contacts app needs are missing, open an Activity
+ * to prompt user for these permissions. After that calling activity is restarted
+ * and in the second run permission check is skipped.
+ *
+ * This is designed to be called inside {@link android.app.Activity#onCreate}
+ */
+ public static boolean startPermissionActivity(Activity activity) {
+ final Bundle extras = activity.getIntent().getExtras();
+ if (extras != null && extras.getBoolean(EXTRA_STARTED_PERMISSIONS_ACTIVITY, false)) {
+ return false;
+ }
+ return startPermissionActivity(activity,
+ getPermissions(activity.getPackageManager()),
+ RequestDesiredPermissionsActivity.class);
+ }
+
+ private static String[] getPermissions(PackageManager packageManager) {
+ if (sDesiredPermissions == null) {
+ final List<String> permissions = new ArrayList<>();
+ // Calendar group
+ permissions.add(permission.READ_CALENDAR);
+
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ // SMS group
+ permissions.add(permission.READ_SMS);
+ }
+ sDesiredPermissions = permissions.toArray(new String[0]);
+ }
+ return sDesiredPermissions;
+ }
+
+ @Override
+ public void onRequestPermissionsResult(
+ int requestCode, String permissions[], int[] grantResults) {
+ mPreviousActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ startActivity(mPreviousActivityIntent);
+ overridePendingTransition(0, 0);
+
+ finish();
+ overridePendingTransition(0, 0);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/common/activity/RequestImportVCardPermissionsActivity.java b/src/com/android/contacts/common/activity/RequestImportVCardPermissionsActivity.java
new file mode 100644
index 0000000..df98d12
--- /dev/null
+++ b/src/com/android/contacts/common/activity/RequestImportVCardPermissionsActivity.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 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.common.activity;
+
+import android.Manifest.permission;
+import android.app.Activity;
+
+/**
+ * Activity that requests permissions needed for ImportVCardActivity.
+ */
+public class RequestImportVCardPermissionsActivity extends RequestPermissionsActivity {
+
+ private static final String[] REQUIRED_PERMISSIONS = new String[] {
+ // Contacts group
+ permission.GET_ACCOUNTS,
+ permission.READ_CONTACTS,
+ permission.WRITE_CONTACTS,
+ // Storage group
+ permission.READ_EXTERNAL_STORAGE,
+ };
+
+ @Override
+ protected String[] getPermissions() {
+ return REQUIRED_PERMISSIONS;
+ }
+
+ /**
+ * If any permissions the Contacts app needs are missing, open an Activity
+ * to prompt the user for these permissions. Moreover, finish the current activity.
+ *
+ * This is designed to be called inside {@link android.app.Activity#onCreate}
+ */
+ public static boolean startPermissionActivity(Activity activity) {
+ return startPermissionActivity(activity, REQUIRED_PERMISSIONS,
+ RequestImportVCardPermissionsActivity.class);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/common/activity/RequestPermissionsActivity.java b/src/com/android/contacts/common/activity/RequestPermissionsActivity.java
new file mode 100644
index 0000000..126cd64
--- /dev/null
+++ b/src/com/android/contacts/common/activity/RequestPermissionsActivity.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 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.common.activity;
+
+import com.android.contacts.common.R;
+
+import android.Manifest.permission;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Activity that requests permissions needed for activities exported from Contacts.
+ */
+public class RequestPermissionsActivity extends RequestPermissionsActivityBase {
+
+ private static String[] sRequiredPermissions;
+
+ @Override
+ protected String[] getPermissions() {
+ return getPermissions(getPackageManager());
+ }
+
+ public static boolean startPermissionActivity(Activity activity) {
+ return startPermissionActivity(activity,
+ getPermissions(activity.getPackageManager()),
+ RequestPermissionsActivity.class);
+ }
+
+ private static String[] getPermissions(PackageManager packageManager) {
+ if (sRequiredPermissions == null) {
+ final List<String> permissions = new ArrayList<>();
+ // Contacts group
+ permissions.add(permission.GET_ACCOUNTS);
+ permissions.add(permission.READ_CONTACTS);
+ permissions.add(permission.WRITE_CONTACTS);
+
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ // Phone group
+ // These are only used in a few places such as QuickContactActivity and
+ // ImportExportDialogFragment. We work around missing this permission when
+ // telephony is not available on the device (i.e. on tablets).
+ permissions.add(permission.CALL_PHONE);
+ permissions.add(permission.READ_CALL_LOG);
+ permissions.add(permission.READ_PHONE_STATE);
+ }
+ sRequiredPermissions = permissions.toArray(new String[0]);
+ }
+ return sRequiredPermissions;
+ }
+
+ @Override
+ public void onRequestPermissionsResult(
+ int requestCode, String permissions[], int[] grantResults) {
+ if (permissions != null && permissions.length > 0
+ && isAllGranted(permissions, grantResults)) {
+ mPreviousActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+ startActivity(mPreviousActivityIntent);
+ finish();
+ overridePendingTransition(0, 0);
+ } else {
+ Toast.makeText(this, R.string.missing_required_permission, Toast.LENGTH_SHORT).show();
+ finish();
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/activity/RequestPermissionsActivityBase.java b/src/com/android/contacts/common/activity/RequestPermissionsActivityBase.java
new file mode 100644
index 0000000..999c545
--- /dev/null
+++ b/src/com/android/contacts/common/activity/RequestPermissionsActivityBase.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2015 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.common.activity;
+
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.util.PermissionsUtil;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Trace;
+import android.support.v4.app.ActivityCompat;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Activity that asks the user for all {@link #getPermissions} if any are missing.
+ *
+ * NOTE: As a result of b/22095159, this can behave oddly in the case where the final permission
+ * you are requesting causes an application restart.
+ */
+public abstract class RequestPermissionsActivityBase extends Activity
+ implements ActivityCompat.OnRequestPermissionsResultCallback {
+
+ public static final String PREVIOUS_ACTIVITY_INTENT = "previous_intent";
+
+ /** Whether the permissions activity was already started. */
+ protected static final String EXTRA_STARTED_PERMISSIONS_ACTIVITY =
+ "started_permissions_activity";
+
+ private static final int PERMISSIONS_REQUEST_ALL_PERMISSIONS = 1;
+
+ /**
+ * @return list of permissions that are needed in order for {@link #PREVIOUS_ACTIVITY_INTENT}
+ * to operate. You only need to return a single permission per permission group you care about.
+ */
+ protected abstract String[] getPermissions();
+
+ protected Intent mPreviousActivityIntent;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mPreviousActivityIntent = (Intent) getIntent().getExtras().get(PREVIOUS_ACTIVITY_INTENT);
+
+ // Only start a requestPermissions() flow when first starting this activity the first time.
+ // The process is likely to be restarted during the permission flow (necessary to enable
+ // permissions) so this is important to track.
+ if (savedInstanceState == null) {
+ requestPermissions();
+ }
+ }
+
+ /**
+ * If any permissions the Contacts app needs are missing, open an Activity
+ * to prompt the user for these permissions. Moreover, finish the current activity.
+ *
+ * This is designed to be called inside {@link android.app.Activity#onCreate}
+ */
+ protected static boolean startPermissionActivity(Activity activity,
+ String[] requiredPermissions, Class<?> newActivityClass) {
+ if (!hasPermissions(activity, requiredPermissions)) {
+ final Intent intent = new Intent(activity, newActivityClass);
+ activity.getIntent().putExtra(EXTRA_STARTED_PERMISSIONS_ACTIVITY, true);
+ intent.putExtra(PREVIOUS_ACTIVITY_INTENT, activity.getIntent());
+ activity.startActivity(intent);
+ activity.finish();
+ return true;
+ }
+
+ // Account type initialization must be delayed until the Contacts permission group
+ // has been granted (since GET_ACCOUNTS) falls under that groups. Previously it
+ // was initialized in ContactApplication which would cause problems as
+ // AccountManager.getAccounts would return an empty array. See b/22690336
+ AccountTypeManager.getInstance(activity);
+
+ return false;
+ }
+
+ protected boolean isAllGranted(String permissions[], int[] grantResult) {
+ for (int i = 0; i < permissions.length; i++) {
+ if (grantResult[i] != PackageManager.PERMISSION_GRANTED
+ && isPermissionRequired(permissions[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean isPermissionRequired(String p) {
+ return Arrays.asList(getPermissions()).contains(p);
+ }
+
+ private void requestPermissions() {
+ Trace.beginSection("requestPermissions");
+ try {
+ // Construct a list of missing permissions
+ final ArrayList<String> unsatisfiedPermissions = new ArrayList<>();
+ for (String permission : getPermissions()) {
+ if (!PermissionsUtil.hasPermission(this, permission)) {
+ unsatisfiedPermissions.add(permission);
+ }
+ }
+ if (unsatisfiedPermissions.size() == 0) {
+ throw new RuntimeException("Request permission activity was called even"
+ + " though all permissions are satisfied.");
+ }
+ ActivityCompat.requestPermissions(
+ this,
+ unsatisfiedPermissions.toArray(new String[unsatisfiedPermissions.size()]),
+ PERMISSIONS_REQUEST_ALL_PERMISSIONS);
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ protected static boolean hasPermissions(Context context, String[] permissions) {
+ Trace.beginSection("hasPermission");
+ try {
+ for (String permission : permissions) {
+ if (!PermissionsUtil.hasPermission(context, permission)) {
+ return false;
+ }
+ }
+ return true;
+ } finally {
+ Trace.endSection();
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/activity/TransactionSafeActivity.java b/src/com/android/contacts/common/activity/TransactionSafeActivity.java
new file mode 100644
index 0000000..6c2e4fe
--- /dev/null
+++ b/src/com/android/contacts/common/activity/TransactionSafeActivity.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 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.common.activity;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * A common superclass that keeps track of whether an {@link Activity} has saved its state yet or
+ * not.
+ */
+public abstract class TransactionSafeActivity extends Activity {
+
+ private boolean mIsSafeToCommitTransactions;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mIsSafeToCommitTransactions = true;
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mIsSafeToCommitTransactions = true;
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mIsSafeToCommitTransactions = true;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mIsSafeToCommitTransactions = false;
+ }
+
+ /**
+ * Returns true if it is safe to commit {@link FragmentTransaction}s at this time, based on
+ * whether {@link Activity#onSaveInstanceState} has been called or not.
+ *
+ * Make sure that the current activity calls into
+ * {@link super.onSaveInstanceState(Bundle outState)} (if that method is overridden),
+ * so the flag is properly set.
+ */
+ public boolean isSafeToCommitTransactions() {
+ return mIsSafeToCommitTransactions;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/CallSdkCompat.java b/src/com/android/contacts/common/compat/CallSdkCompat.java
new file mode 100644
index 0000000..fd06d85
--- /dev/null
+++ b/src/com/android/contacts/common/compat/CallSdkCompat.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 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.common.compat;
+
+import android.telecom.Call;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class CallSdkCompat {
+ public static class Details {
+ // TODO: This property is hidden in the N release; replace with actual when the API is
+ // made public.
+ public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040;
+ public static final int PROPERTY_ENTERPRISE_CALL = Call.Details.PROPERTY_ENTERPRISE_CALL;
+ // TODO: This capability is hidden in the N release; replace with actual when the API is
+ // made public.
+ public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
+ public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO =
+ Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO;
+ }
+
+ /**
+ * TODO: This API is hidden in the N release; replace the implementation with a call to the
+ * actual once it is made public.
+ */
+ public static void pullExternalCall(Call call) {
+ if (!CompatUtils.isNCompatible()) {
+ return;
+ }
+ Class<?> callClass = Call.class;
+ try {
+ Method pullExternalCallMethod = callClass.getDeclaredMethod("pullExternalCall");
+ pullExternalCallMethod.invoke(call);
+ } catch (NoSuchMethodException e) {
+ // Ignore requests to pull call if there is a problem.
+ } catch (InvocationTargetException e) {
+ // Ignore requests to pull call if there is a problem.
+ } catch (IllegalAccessException e) {
+ // Ignore requests to pull call if there is a problem.
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/compat/CallableCompat.java b/src/com/android/contacts/common/compat/CallableCompat.java
new file mode 100644
index 0000000..d25d4be
--- /dev/null
+++ b/src/com/android/contacts/common/compat/CallableCompat.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.net.Uri;
+import android.provider.ContactsContract.CommonDataKinds.Callable;
+
+import com.android.contacts.common.ContactsUtils;
+
+public class CallableCompat {
+
+ // TODO: Use N APIs
+ private static final Uri ENTERPRISE_CONTENT_FILTER_URI =
+ Uri.withAppendedPath(Callable.CONTENT_URI, "filter_enterprise");
+
+ public static Uri getContentFilterUri() {
+ if (ContactsUtils.FLAG_N_FEATURE) {
+ return ENTERPRISE_CONTENT_FILTER_URI;
+ }
+ return Callable.CONTENT_FILTER_URI;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/CompatUtils.java b/src/com/android/contacts/common/compat/CompatUtils.java
new file mode 100644
index 0000000..567f183
--- /dev/null
+++ b/src/com/android/contacts/common/compat/CompatUtils.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.os.Build;
+import android.os.Build.VERSION;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.contacts.common.model.CPOWrapper;
+
+import java.lang.reflect.InvocationTargetException;
+
+public final class CompatUtils {
+
+ private static final String TAG = CompatUtils.class.getSimpleName();
+
+ /**
+ * These 4 variables are copied from ContentProviderOperation for compatibility.
+ */
+ public final static int TYPE_INSERT = 1;
+
+ public final static int TYPE_UPDATE = 2;
+
+ public final static int TYPE_DELETE = 3;
+
+ public final static int TYPE_ASSERT = 4;
+
+ /**
+ * Returns whether the operation in CPOWrapper is of TYPE_INSERT;
+ */
+ public static boolean isInsertCompat(CPOWrapper cpoWrapper) {
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
+ return cpoWrapper.getOperation().isInsert();
+ }
+ return (cpoWrapper.getType() == TYPE_INSERT);
+ }
+
+ /**
+ * Returns whether the operation in CPOWrapper is of TYPE_UPDATE;
+ */
+ public static boolean isUpdateCompat(CPOWrapper cpoWrapper) {
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
+ return cpoWrapper.getOperation().isUpdate();
+ }
+ return (cpoWrapper.getType() == TYPE_UPDATE);
+ }
+
+ /**
+ * Returns whether the operation in CPOWrapper is of TYPE_DELETE;
+ */
+ public static boolean isDeleteCompat(CPOWrapper cpoWrapper) {
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
+ return cpoWrapper.getOperation().isDelete();
+ }
+ return (cpoWrapper.getType() == TYPE_DELETE);
+ }
+ /**
+ * Returns whether the operation in CPOWrapper is of TYPE_ASSERT;
+ */
+ public static boolean isAssertQueryCompat(CPOWrapper cpoWrapper) {
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
+ return cpoWrapper.getOperation().isAssertQuery();
+ }
+ return (cpoWrapper.getType() == TYPE_ASSERT);
+ }
+
+ /**
+ * PrioritizedMimeType is added in API level 23.
+ */
+ public static boolean hasPrioritizedMimeType() {
+ return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
+ >= Build.VERSION_CODES.M;
+ }
+
+ /**
+ * Determines if this version is compatible with multi-SIM and the phone account APIs. Can also
+ * force the version to be lower through SdkVersionOverride.
+ *
+ * @return {@code true} if multi-SIM capability is available, {@code false} otherwise.
+ */
+ public static boolean isMSIMCompatible() {
+ return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
+ >= Build.VERSION_CODES.LOLLIPOP_MR1;
+ }
+
+ /**
+ * Determines if this version is compatible with video calling. Can also force the version to be
+ * lower through SdkVersionOverride.
+ *
+ * @return {@code true} if video calling is allowed, {@code false} otherwise.
+ */
+ public static boolean isVideoCompatible() {
+ return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
+ >= Build.VERSION_CODES.M;
+ }
+
+ /**
+ * Determines if this version is capable of using presence checking for video calling. Support
+ * for video call presence indication is added in SDK 24.
+ *
+ * @return {@code true} if video presence checking is allowed, {@code false} otherwise.
+ */
+ public static boolean isVideoPresenceCompatible() {
+ return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
+ > Build.VERSION_CODES.M;
+ }
+
+ /**
+ * Determines if this version is compatible with call subject. Can also force the version to be
+ * lower through SdkVersionOverride.
+ *
+ * @return {@code true} if call subject is a feature on this device, {@code false} otherwise.
+ */
+ public static boolean isCallSubjectCompatible() {
+ return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
+ >= Build.VERSION_CODES.M;
+ }
+
+ /**
+ * Determines if this version is compatible with a default dialer. Can also force the version to
+ * be lower through {@link SdkVersionOverride}.
+ *
+ * @return {@code true} if default dialer is a feature on this device, {@code false} otherwise.
+ */
+ public static boolean isDefaultDialerCompatible() {
+ return isMarshmallowCompatible();
+ }
+
+ /**
+ * Determines if this version is compatible with Lollipop Mr1-specific APIs. Can also force the
+ * version to be lower through SdkVersionOverride.
+ *
+ * @return {@code true} if runtime sdk is compatible with Lollipop MR1, {@code false} otherwise.
+ */
+ public static boolean isLollipopMr1Compatible() {
+ return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP_MR1)
+ >= Build.VERSION_CODES.LOLLIPOP_MR1;
+ }
+
+ /**
+ * Determines if this version is compatible with Marshmallow-specific APIs. Can also force the
+ * version to be lower through SdkVersionOverride.
+ *
+ * @return {@code true} if runtime sdk is compatible with Marshmallow, {@code false} otherwise.
+ */
+ public static boolean isMarshmallowCompatible() {
+ return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
+ >= Build.VERSION_CODES.M;
+ }
+
+ /**
+ * Determines if this version is compatible with N-specific APIs.
+ *
+ * @return {@code true} if runtime sdk is compatible with N and the app is built with N, {@code
+ * false} otherwise.
+ */
+ public static boolean isNCompatible() {
+ return VERSION.SDK_INT >= 24;
+ }
+
+ /**
+ * Determines if the given class is available. Can be used to check if system apis exist at
+ * runtime.
+ *
+ * @param className the name of the class to look for.
+ * @return {@code true} if the given class is available, {@code false} otherwise or if className
+ * is empty.
+ */
+ public static boolean isClassAvailable(@Nullable String className) {
+ if (TextUtils.isEmpty(className)) {
+ return false;
+ }
+ try {
+ Class.forName(className);
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ } catch (Throwable t) {
+ Log.e(TAG, "Unexpected exception when checking if class:" + className + " exists at "
+ + "runtime", t);
+ return false;
+ }
+ }
+
+ /**
+ * Determines if the given class's method is available to call. Can be used to check if system
+ * apis exist at runtime.
+ *
+ * @param className the name of the class to look for
+ * @param methodName the name of the method to look for
+ * @param parameterTypes the needed parameter types for the method to look for
+ * @return {@code true} if the given class is available, {@code false} otherwise or if className
+ * or methodName are empty.
+ */
+ public static boolean isMethodAvailable(@Nullable String className, @Nullable String methodName,
+ Class<?>... parameterTypes) {
+ if (TextUtils.isEmpty(className) || TextUtils.isEmpty(methodName)) {
+ return false;
+ }
+
+ try {
+ Class.forName(className).getMethod(methodName, parameterTypes);
+ return true;
+ } catch (ClassNotFoundException | NoSuchMethodException e) {
+ Log.v(TAG, "Could not find method: " + className + "#" + methodName);
+ return false;
+ } catch (Throwable t) {
+ Log.e(TAG, "Unexpected exception when checking if method: " + className + "#"
+ + methodName + " exists at runtime", t);
+ return false;
+ }
+ }
+
+ /**
+ * Invokes a given class's method using reflection. Can be used to call system apis that exist
+ * at runtime but not in the SDK.
+ *
+ * @param instance The instance of the class to invoke the method on.
+ * @param methodName The name of the method to invoke.
+ * @param parameterTypes The needed parameter types for the method.
+ * @param parameters The parameter values to pass into the method.
+ * @return The result of the invocation or {@code null} if instance or methodName are empty, or
+ * if the reflection fails.
+ */
+ @Nullable
+ public static Object invokeMethod(@Nullable Object instance, @Nullable String methodName,
+ Class<?>[] parameterTypes, Object[] parameters) {
+ if (instance == null || TextUtils.isEmpty(methodName)) {
+ return null;
+ }
+
+ String className = instance.getClass().getName();
+ try {
+ return Class.forName(className).getMethod(methodName, parameterTypes)
+ .invoke(instance, parameters);
+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalArgumentException
+ | IllegalAccessException | InvocationTargetException e) {
+ Log.v(TAG, "Could not invoke method: " + className + "#" + methodName);
+ return null;
+ } catch (Throwable t) {
+ Log.e(TAG, "Unexpected exception when invoking method: " + className
+ + "#" + methodName + " at runtime", t);
+ return null;
+ }
+ }
+
+ /**
+ * Determines if this version is compatible with Lollipop-specific APIs. Can also force the
+ * version to be lower through SdkVersionOverride.
+ *
+ * @return {@code true} if call subject is a feature on this device, {@code false} otherwise.
+ */
+ public static boolean isLollipopCompatible() {
+ return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
+ >= Build.VERSION_CODES.LOLLIPOP;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/ContactsCompat.java b/src/com/android/contacts/common/compat/ContactsCompat.java
new file mode 100644
index 0000000..5a5e46a
--- /dev/null
+++ b/src/com/android/contacts/common/compat/ContactsCompat.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+
+import com.android.contacts.common.ContactsUtils;
+
+/**
+ * Compatibility class for {@link ContactsContract.Contacts}
+ */
+public class ContactsCompat {
+ /**
+ * Not instantiable.
+ */
+ private ContactsCompat() {
+ }
+
+ // TODO: Use N APIs
+ private static final Uri ENTERPRISE_CONTENT_FILTER_URI =
+ Uri.withAppendedPath(Contacts.CONTENT_URI, "filter_enterprise");
+
+ // Copied from ContactsContract.Contacts#ENTERPRISE_CONTACT_ID_BASE, which is hidden.
+ private static final long ENTERPRISE_CONTACT_ID_BASE = 1000000000;
+
+ public static Uri getContentUri() {
+ if (ContactsUtils.FLAG_N_FEATURE) {
+ return ENTERPRISE_CONTENT_FILTER_URI;
+ }
+ return Contacts.CONTENT_FILTER_URI;
+ }
+
+ /**
+ * Return {@code true} if a contact ID is from the contacts provider on the enterprise profile.
+ */
+ public static boolean isEnterpriseContactId(long contactId) {
+ if (CompatUtils.isLollipopCompatible()) {
+ return Contacts.isEnterpriseContactId(contactId);
+ } else {
+ // copied from ContactsContract.Contacts.isEnterpriseContactId
+ return (contactId >= ENTERPRISE_CONTACT_ID_BASE) &&
+ (contactId < ContactsContract.Profile.MIN_ID);
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/compat/DirectoryCompat.java b/src/com/android/contacts/common/compat/DirectoryCompat.java
new file mode 100644
index 0000000..682e14c
--- /dev/null
+++ b/src/com/android/contacts/common/compat/DirectoryCompat.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Directory;
+
+import com.android.contacts.common.ContactsUtils;
+
+public class DirectoryCompat {
+
+ public static Uri getContentUri() {
+ if (ContactsUtils.FLAG_N_FEATURE) {
+ return DirectorySdkCompat.ENTERPRISE_CONTENT_URI;
+ }
+ return Directory.CONTENT_URI;
+ }
+
+ public static boolean isInvisibleDirectory(long directoryId) {
+ if (ContactsUtils.FLAG_N_FEATURE) {
+ return (directoryId == Directory.LOCAL_INVISIBLE
+ || directoryId == DirectorySdkCompat.ENTERPRISE_LOCAL_INVISIBLE);
+ }
+ return directoryId == Directory.LOCAL_INVISIBLE;
+ }
+
+ public static boolean isRemoteDirectoryId(long directoryId) {
+ if (ContactsUtils.FLAG_N_FEATURE) {
+ return DirectorySdkCompat.isRemoteDirectoryId(directoryId);
+ }
+ return !(directoryId == Directory.DEFAULT || directoryId == Directory.LOCAL_INVISIBLE);
+ }
+
+ public static boolean isEnterpriseDirectoryId(long directoryId) {
+ return ContactsUtils.FLAG_N_FEATURE
+ ? DirectorySdkCompat.isEnterpriseDirectoryId(directoryId)
+ : false;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/DirectorySdkCompat.java b/src/com/android/contacts/common/compat/DirectorySdkCompat.java
new file mode 100644
index 0000000..b919466
--- /dev/null
+++ b/src/com/android/contacts/common/compat/DirectorySdkCompat.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.net.Uri;
+import android.provider.ContactsContract.Directory;
+
+public class DirectorySdkCompat {
+
+ private static final String TAG = "DirectorySdkCompat";
+
+ public static final Uri ENTERPRISE_CONTENT_URI = Directory.ENTERPRISE_CONTENT_URI;
+ public static final long ENTERPRISE_LOCAL_DEFAULT = Directory.ENTERPRISE_DEFAULT;
+ public static final long ENTERPRISE_LOCAL_INVISIBLE = Directory.ENTERPRISE_LOCAL_INVISIBLE;
+
+ public static boolean isRemoteDirectoryId(long directoryId) {
+ return CompatUtils.isNCompatible() ? Directory.isRemoteDirectoryId(directoryId) : false;
+ }
+
+ public static boolean isEnterpriseDirectoryId(long directoryId) {
+ return CompatUtils.isNCompatible() ? Directory.isEnterpriseDirectoryId(directoryId) : false;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/EventCompat.java b/src/com/android/contacts/common/compat/EventCompat.java
new file mode 100644
index 0000000..f37aeff
--- /dev/null
+++ b/src/com/android/contacts/common/compat/EventCompat.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.content.res.Resources;
+import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.text.TextUtils;
+
+/**
+ * Compatibility class for {@link Event}
+ */
+public class EventCompat {
+ /**
+ * Not instantiable.
+ */
+ private EventCompat() {
+ }
+
+ /**
+ * Return a {@link CharSequence} that best describes the given type, possibly substituting
+ * the given label value for TYPE_CUSTOM.
+ */
+ public static CharSequence getTypeLabel(Resources res, int type, CharSequence label) {
+ if (CompatUtils.isLollipopCompatible()) {
+ return Event.getTypeLabel(res, type, label);
+ } else {
+ return getTypeLabelInternal(res, type, label);
+ }
+ }
+
+ /**
+ * The method was added in API level 21, and below is the implementation copied from
+ * {@link Event#getTypeLabel(Resources, int, CharSequence)}
+ */
+ private static CharSequence getTypeLabelInternal(Resources res, int type, CharSequence label) {
+ if (type == BaseTypes.TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+ return label;
+ } else {
+ return res.getText(Event.getTypeResource(type));
+ }
+ }
+
+}
diff --git a/src/com/android/contacts/common/compat/MetadataSyncEnabledCompat.java b/src/com/android/contacts/common/compat/MetadataSyncEnabledCompat.java
new file mode 100644
index 0000000..4a9650f
--- /dev/null
+++ b/src/com/android/contacts/common/compat/MetadataSyncEnabledCompat.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 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.common.compat;
+
+import android.content.Context;
+import android.provider.Settings;
+
+public class MetadataSyncEnabledCompat {
+ public static boolean isMetadataSyncEnabled(Context context) {
+ return CompatUtils.isNCompatible()
+ ? (Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.CONTACT_METADATA_SYNC_ENABLED, 0) == 1)
+ : false;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/common/compat/MultiWindowCompat.java b/src/com/android/contacts/common/compat/MultiWindowCompat.java
new file mode 100644
index 0000000..6641279
--- /dev/null
+++ b/src/com/android/contacts/common/compat/MultiWindowCompat.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 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.common.compat;
+
+import android.app.Activity;
+
+public class MultiWindowCompat {
+ /**
+ * Returns true if the activity is currently in multi-window mode.
+ */
+ public static boolean isInMultiWindowMode(Activity activity) {
+ return CompatUtils.isNCompatible() ? activity.isInMultiWindowMode() : false;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/common/compat/PhoneAccountCompat.java b/src/com/android/contacts/common/compat/PhoneAccountCompat.java
new file mode 100644
index 0000000..00f4211
--- /dev/null
+++ b/src/com/android/contacts/common/compat/PhoneAccountCompat.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.support.annotation.Nullable;
+import android.telecom.PhoneAccount;
+import android.util.Log;
+
+/**
+ * Compatiblity class for {@link android.telecom.PhoneAccount}
+ */
+public class PhoneAccountCompat {
+
+ private static final String TAG = PhoneAccountCompat.class.getSimpleName();
+
+ /**
+ * Gets the {@link Icon} associated with the given {@link PhoneAccount}
+ *
+ * @param phoneAccount the PhoneAccount from which to retrieve the Icon
+ * @return the Icon, or null
+ */
+ @Nullable
+ public static Icon getIcon(@Nullable PhoneAccount phoneAccount) {
+ if (phoneAccount == null) {
+ return null;
+ }
+
+ if (CompatUtils.isMarshmallowCompatible()) {
+ return phoneAccount.getIcon();
+ }
+
+ return null;
+ }
+
+ /**
+ * Builds and returns an icon {@code Drawable} to represent this {@code PhoneAccount} in a user
+ * interface.
+ *
+ * @param phoneAccount the PhoneAccount from which to build the icon.
+ * @param context A {@code Context} to use for loading Drawables.
+ *
+ * @return An icon for this PhoneAccount, or null
+ */
+ @Nullable
+ public static Drawable createIconDrawable(@Nullable PhoneAccount phoneAccount,
+ @Nullable Context context) {
+ if (phoneAccount == null || context == null) {
+ return null;
+ }
+
+ if (CompatUtils.isMarshmallowCompatible()) {
+ return createIconDrawableMarshmallow(phoneAccount, context);
+ }
+
+ if (CompatUtils.isLollipopMr1Compatible()) {
+ return createIconDrawableLollipopMr1(phoneAccount, context);
+ }
+ return null;
+ }
+
+ @Nullable
+ private static Drawable createIconDrawableMarshmallow(PhoneAccount phoneAccount,
+ Context context) {
+ Icon accountIcon = getIcon(phoneAccount);
+ if (accountIcon == null) {
+ return null;
+ }
+ return accountIcon.loadDrawable(context);
+ }
+
+ @Nullable
+ private static Drawable createIconDrawableLollipopMr1(PhoneAccount phoneAccount,
+ Context context) {
+ try {
+ return (Drawable) PhoneAccount.class.getMethod("createIconDrawable", Context.class)
+ .invoke(phoneAccount, context);
+ } catch (ReflectiveOperationException e) {
+ return null;
+ } catch (Throwable t) {
+ Log.e(TAG, "Unexpected exception when attempting to call "
+ + "android.telecom.PhoneAccount#createIconDrawable", t);
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/compat/PhoneAccountSdkCompat.java b/src/com/android/contacts/common/compat/PhoneAccountSdkCompat.java
new file mode 100644
index 0000000..5cbf617
--- /dev/null
+++ b/src/com/android/contacts/common/compat/PhoneAccountSdkCompat.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.os.Bundle;
+import android.telecom.PhoneAccount;
+
+public class PhoneAccountSdkCompat {
+
+ private static final String TAG = "PhoneAccountSdkCompat";
+
+ public static final String EXTRA_CALL_SUBJECT_MAX_LENGTH =
+ PhoneAccount.EXTRA_CALL_SUBJECT_MAX_LENGTH;
+ public static final String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING =
+ PhoneAccount.EXTRA_CALL_SUBJECT_CHARACTER_ENCODING;
+
+ public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE =
+ PhoneAccount.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE;
+
+ public static Bundle getExtras(PhoneAccount account) {
+ return CompatUtils.isNCompatible() ? account.getExtras() : null;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/PhoneCompat.java b/src/com/android/contacts/common/compat/PhoneCompat.java
new file mode 100644
index 0000000..5277761
--- /dev/null
+++ b/src/com/android/contacts/common/compat/PhoneCompat.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.net.Uri;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+
+import com.android.contacts.common.ContactsUtils;
+
+public class PhoneCompat {
+
+ // TODO: Use N APIs
+ private static final Uri ENTERPRISE_CONTENT_FILTER_URI =
+ Uri.withAppendedPath(Phone.CONTENT_URI, "filter_enterprise");
+
+ public static Uri getContentFilterUri() {
+ if (ContactsUtils.FLAG_N_FEATURE) {
+ return ENTERPRISE_CONTENT_FILTER_URI;
+ }
+ return Phone.CONTENT_FILTER_URI;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/PhoneLookupSdkCompat.java b/src/com/android/contacts/common/compat/PhoneLookupSdkCompat.java
new file mode 100644
index 0000000..0c0a898
--- /dev/null
+++ b/src/com/android/contacts/common/compat/PhoneLookupSdkCompat.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 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.common.compat;
+
+import android.provider.ContactsContract;
+
+public class PhoneLookupSdkCompat {
+ public static final String CONTACT_ID = ContactsContract.PhoneLookup.CONTACT_ID;
+}
diff --git a/src/com/android/contacts/common/compat/PhoneNumberFormattingTextWatcherCompat.java b/src/com/android/contacts/common/compat/PhoneNumberFormattingTextWatcherCompat.java
new file mode 100644
index 0000000..42b604e
--- /dev/null
+++ b/src/com/android/contacts/common/compat/PhoneNumberFormattingTextWatcherCompat.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.telephony.PhoneNumberFormattingTextWatcher;
+
+public class PhoneNumberFormattingTextWatcherCompat {
+ public static PhoneNumberFormattingTextWatcher newInstance(String countryCode) {
+ if (CompatUtils.isLollipopCompatible()) {
+ return new PhoneNumberFormattingTextWatcher(countryCode);
+ }
+ return new PhoneNumberFormattingTextWatcher();
+ }
+}
diff --git a/src/com/android/contacts/common/compat/PhoneNumberUtilsCompat.java b/src/com/android/contacts/common/compat/PhoneNumberUtilsCompat.java
new file mode 100644
index 0000000..9a8fa41
--- /dev/null
+++ b/src/com/android/contacts/common/compat/PhoneNumberUtilsCompat.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+
+import android.telephony.PhoneNumberUtils;
+import android.text.Spannable;
+import android.text.TextUtils;
+import android.text.style.TtsSpan;
+
+/**
+ * This class contains static utility methods extracted from PhoneNumberUtils, and the
+ * methods were added in API level 23. In this way, we could enable the corresponding functionality
+ * for pre-M devices. We need maintain this class and keep it synced with PhoneNumberUtils.
+ * Another thing to keep in mind is that we use com.google.i18n rather than com.android.i18n in
+ * here, so we need make sure the application behavior is preserved.
+ */
+public class PhoneNumberUtilsCompat {
+ /**
+ * Not instantiable.
+ */
+ private PhoneNumberUtilsCompat() {}
+
+ public static String normalizeNumber(String phoneNumber) {
+ if (CompatUtils.isLollipopCompatible()) {
+ return PhoneNumberUtils.normalizeNumber(phoneNumber);
+ } else {
+ return normalizeNumberInternal(phoneNumber);
+ }
+ }
+
+ /**
+ * Implementation copied from {@link PhoneNumberUtils#normalizeNumber}
+ */
+ private static String normalizeNumberInternal(String phoneNumber) {
+ if (TextUtils.isEmpty(phoneNumber)) {
+ return "";
+ }
+ StringBuilder sb = new StringBuilder();
+ int len = phoneNumber.length();
+ for (int i = 0; i < len; i++) {
+ char c = phoneNumber.charAt(i);
+ // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
+ int digit = Character.digit(c, 10);
+ if (digit != -1) {
+ sb.append(digit);
+ } else if (sb.length() == 0 && c == '+') {
+ sb.append(c);
+ } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ return normalizeNumber(PhoneNumberUtils.convertKeypadLettersToDigits(phoneNumber));
+ }
+ }
+ return sb.toString();
+ }
+
+ public static String formatNumber(
+ String phoneNumber, String phoneNumberE164, String defaultCountryIso) {
+ if (CompatUtils.isLollipopCompatible()) {
+ return PhoneNumberUtils.formatNumber(phoneNumber, phoneNumberE164, defaultCountryIso);
+ } else {
+ // This method was deprecated in API level 21, so it's only used on pre-L SDKs.
+ return PhoneNumberUtils.formatNumber(phoneNumber);
+ }
+ }
+
+ public static CharSequence createTtsSpannable(CharSequence phoneNumber) {
+ if (CompatUtils.isMarshmallowCompatible()) {
+ return PhoneNumberUtils.createTtsSpannable(phoneNumber);
+ } else {
+ return createTtsSpannableInternal(phoneNumber);
+ }
+ }
+
+ public static TtsSpan createTtsSpan(String phoneNumber) {
+ if (CompatUtils.isMarshmallowCompatible()) {
+ return PhoneNumberUtils.createTtsSpan(phoneNumber);
+ } else if (CompatUtils.isLollipopCompatible()) {
+ return createTtsSpanLollipop(phoneNumber);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Copied from {@link PhoneNumberUtils#createTtsSpannable}
+ */
+ private static CharSequence createTtsSpannableInternal(CharSequence phoneNumber) {
+ if (phoneNumber == null) {
+ return null;
+ }
+ Spannable spannable = Spannable.Factory.getInstance().newSpannable(phoneNumber);
+ addTtsSpanInternal(spannable, 0, spannable.length());
+ return spannable;
+ }
+
+ /**
+ * Compat method for addTtsSpan, see {@link PhoneNumberUtils#addTtsSpan}
+ */
+ public static void addTtsSpan(Spannable s, int start, int endExclusive) {
+ if (CompatUtils.isMarshmallowCompatible()) {
+ PhoneNumberUtils.addTtsSpan(s, start, endExclusive);
+ } else {
+ addTtsSpanInternal(s, start, endExclusive);
+ }
+ }
+
+ /**
+ * Copied from {@link PhoneNumberUtils#addTtsSpan}
+ */
+ private static void addTtsSpanInternal(Spannable s, int start, int endExclusive) {
+ s.setSpan(createTtsSpan(s.subSequence(start, endExclusive).toString()),
+ start,
+ endExclusive,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+
+ /**
+ * Copied from {@link PhoneNumberUtils#createTtsSpan}
+ */
+ private static TtsSpan createTtsSpanLollipop(String phoneNumberString) {
+ if (phoneNumberString == null) {
+ return null;
+ }
+
+ // Parse the phone number
+ final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
+ PhoneNumber phoneNumber = null;
+ try {
+ // Don't supply a defaultRegion so this fails for non-international numbers because
+ // we don't want to TalkBalk to read a country code (e.g. +1) if it is not already
+ // present
+ phoneNumber = phoneNumberUtil.parse(phoneNumberString, /* defaultRegion */ null);
+ } catch (NumberParseException ignored) {
+ }
+
+ // Build a telephone tts span
+ final TtsSpan.TelephoneBuilder builder = new TtsSpan.TelephoneBuilder();
+ if (phoneNumber == null) {
+ // Strip separators otherwise TalkBack will be silent
+ // (this behavior was observed with TalkBalk 4.0.2 from their alpha channel)
+ builder.setNumberParts(splitAtNonNumerics(phoneNumberString));
+ } else {
+ if (phoneNumber.hasCountryCode()) {
+ builder.setCountryCode(Integer.toString(phoneNumber.getCountryCode()));
+ }
+ builder.setNumberParts(Long.toString(phoneNumber.getNationalNumber()));
+ }
+ return builder.build();
+ }
+
+
+
+ /**
+ * Split a phone number using spaces, ignoring anything that is not a digit
+ * @param number A {@code CharSequence} before splitting, e.g., "+20(123)-456#"
+ * @return A {@code String} after splitting, e.g., "20 123 456".
+ */
+ private static String splitAtNonNumerics(CharSequence number) {
+ StringBuilder sb = new StringBuilder(number.length());
+ for (int i = 0; i < number.length(); i++) {
+ sb.append(PhoneNumberUtils.isISODigit(number.charAt(i))
+ ? number.charAt(i)
+ : " ");
+ }
+ // It is very important to remove extra spaces. At time of writing, any leading or trailing
+ // spaces, or any sequence of more than one space, will confuse TalkBack and cause the TTS
+ // span to be non-functional!
+ return sb.toString().replaceAll(" +", " ").trim();
+ }
+
+}
diff --git a/src/com/android/contacts/common/compat/ProviderStatusCompat.java b/src/com/android/contacts/common/compat/ProviderStatusCompat.java
new file mode 100644
index 0000000..84338de
--- /dev/null
+++ b/src/com/android/contacts/common/compat/ProviderStatusCompat.java
@@ -0,0 +1,70 @@
+
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.os.Build;
+import android.provider.ContactsContract.ProviderStatus;
+
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.SdkVersionOverride;
+
+/**
+ * This class contains constants from the pre-M version of ContactsContract.ProviderStatus class
+ * and also the mappings between pre-M constants and M constants for compatibility purpose,
+ * because ProviderStatus class constant names and values changed and the class became visible in
+ * API level 23.
+ */
+public class ProviderStatusCompat {
+ /**
+ * Not instantiable.
+ */
+ private ProviderStatusCompat() {
+ }
+
+ public static final boolean USE_CURRENT_VERSION = CompatUtils.isMarshmallowCompatible();
+
+ public static final int STATUS_EMPTY = USE_CURRENT_VERSION ?
+ ProviderStatus.STATUS_EMPTY : ProviderStatusCompat.STATUS_NO_ACCOUNTS_NO_CONTACTS;
+
+ public static final int STATUS_BUSY = USE_CURRENT_VERSION ?
+ ProviderStatus.STATUS_BUSY : ProviderStatusCompat.STATUS_UPGRADING;
+
+ /**
+ * Default status of the provider, using the actual constant to guard against errors
+ */
+ public static final int STATUS_NORMAL = ProviderStatus.STATUS_NORMAL;
+
+ /**
+ * The following three constants are from pre-M.
+ *
+ * The status used when the provider is in the process of upgrading. Contacts
+ * are temporarily unaccessible.
+ */
+ private static final int STATUS_UPGRADING = 1;
+
+ /**
+ * The status used during a locale change.
+ */
+ public static final int STATUS_CHANGING_LOCALE = 3;
+
+ /**
+ * The status that indicates that there are no accounts and no contacts
+ * on the device.
+ */
+ private static final int STATUS_NO_ACCOUNTS_NO_CONTACTS = 4;
+}
diff --git a/src/com/android/contacts/common/compat/SdkVersionOverride.java b/src/com/android/contacts/common/compat/SdkVersionOverride.java
new file mode 100644
index 0000000..ebde623
--- /dev/null
+++ b/src/com/android/contacts/common/compat/SdkVersionOverride.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.os.Build.VERSION;
+
+/**
+ * Class used to override the current sdk version to test specific branches of compatibility
+ * logic. When such branching occurs, use {@link #getSdkVersion(int)} rather than explicitly
+ * calling {@link VERSION#SDK_INT}. This allows the sdk version to be forced to a specific value.
+ */
+public class SdkVersionOverride {
+
+ /**
+ * Flag used to determine if override sdk versions are returned.
+ */
+ private static final boolean ALLOW_OVERRIDE_VERSION = false;
+
+ private SdkVersionOverride() {}
+
+ /**
+ * Gets the sdk version
+ *
+ * @param overrideVersion the version to attempt using
+ * @return overrideVersion if the {@link #ALLOW_OVERRIDE_VERSION} flag is set to {@code true},
+ * otherwise the current version
+ */
+ public static int getSdkVersion(int overrideVersion) {
+ return ALLOW_OVERRIDE_VERSION ? overrideVersion : VERSION.SDK_INT;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/TelecomManagerUtil.java b/src/com/android/contacts/common/compat/TelecomManagerUtil.java
new file mode 100644
index 0000000..30c541c
--- /dev/null
+++ b/src/com/android/contacts/common/compat/TelecomManagerUtil.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.common.compat;
+
+import android.content.Intent;
+import android.telecom.TelecomManager;
+
+/**
+ * Utility class for TelecomManager
+ */
+public class TelecomManagerUtil {
+ /**
+ * Creates {@link Intent} to launch the activity to manage blocked numbers.
+ */
+ public static Intent createManageBlockedNumbersIntent(TelecomManager tm) {
+ return CompatUtils.isNCompatible() ? tm.createManageBlockedNumbersIntent() : null;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/TelephonyManagerCompat.java b/src/com/android/contacts/common/compat/TelephonyManagerCompat.java
new file mode 100644
index 0000000..ec7907f
--- /dev/null
+++ b/src/com/android/contacts/common/compat/TelephonyManagerCompat.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.net.Uri;
+import android.support.annotation.Nullable;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyManager;
+
+import com.android.contacts.common.ContactsUtils;
+
+public class TelephonyManagerCompat {
+ public static final String TELEPHONY_MANAGER_CLASS = "android.telephony.TelephonyManager";
+
+ /**
+ * @param telephonyManager The telephony manager instance to use for method calls.
+ * @return true if the current device is "voice capable".
+ * <p>
+ * "Voice capable" means that this device supports circuit-switched
+ * (i.e. voice) phone calls over the telephony network, and is allowed
+ * to display the in-call UI while a cellular voice call is active.
+ * This will be false on "data only" devices which can't make voice
+ * calls and don't support any in-call UI.
+ * <p>
+ * Note: the meaning of this flag is subtly different from the
+ * PackageManager.FEATURE_TELEPHONY system feature, which is available
+ * on any device with a telephony radio, even if the device is
+ * data-only.
+ */
+ public static boolean isVoiceCapable(@Nullable TelephonyManager telephonyManager) {
+ if (telephonyManager == null) {
+ return false;
+ }
+ if (CompatUtils.isLollipopMr1Compatible()
+ || CompatUtils.isMethodAvailable(TELEPHONY_MANAGER_CLASS, "isVoiceCapable")) {
+ // isVoiceCapable was unhidden in L-MR1
+ return telephonyManager.isVoiceCapable();
+ }
+ final int phoneType = telephonyManager.getPhoneType();
+ return phoneType == TelephonyManager.PHONE_TYPE_CDMA ||
+ phoneType == TelephonyManager.PHONE_TYPE_GSM;
+ }
+
+ /**
+ * Returns the number of phones available.
+ * Returns 1 for Single standby mode (Single SIM functionality)
+ * Returns 2 for Dual standby mode.(Dual SIM functionality)
+ *
+ * Returns 1 if the method or telephonyManager is not available.
+ *
+ * @param telephonyManager The telephony manager instance to use for method calls.
+ */
+ public static int getPhoneCount(@Nullable TelephonyManager telephonyManager) {
+ if (telephonyManager == null) {
+ return 1;
+ }
+ if (CompatUtils.isMarshmallowCompatible() || CompatUtils
+ .isMethodAvailable(TELEPHONY_MANAGER_CLASS, "getPhoneCount")) {
+ return telephonyManager.getPhoneCount();
+ }
+ return 1;
+ }
+
+ /**
+ * Returns the unique device ID of a subscription, for example, the IMEI for
+ * GSM and the MEID for CDMA phones. Return null if device ID is not available.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param telephonyManager The telephony manager instance to use for method calls.
+ * @param slotId of which deviceID is returned
+ */
+ public static String getDeviceId(@Nullable TelephonyManager telephonyManager, int slotId) {
+ if (telephonyManager == null) {
+ return null;
+ }
+ if (CompatUtils.isMarshmallowCompatible()
+ || CompatUtils.isMethodAvailable(TELEPHONY_MANAGER_CLASS,
+ "getDeviceId", Integer.class)) {
+ return telephonyManager.getDeviceId(slotId);
+ }
+ return null;
+ }
+
+ /**
+ * Whether the phone supports TTY mode.
+ *
+ * @param telephonyManager The telephony manager instance to use for method calls.
+ * @return {@code true} if the device supports TTY mode, and {@code false} otherwise.
+ */
+
+ public static boolean isTtyModeSupported(@Nullable TelephonyManager telephonyManager) {
+ if (telephonyManager == null) {
+ return false;
+ }
+ if (CompatUtils.isMarshmallowCompatible()
+ || CompatUtils.isMethodAvailable(TELEPHONY_MANAGER_CLASS, "isTtyModeSupported")) {
+ return telephonyManager.isTtyModeSupported();
+ }
+ return false;
+ }
+
+ /**
+ * Whether the phone supports hearing aid compatibility.
+ *
+ * @param telephonyManager The telephony manager instance to use for method calls.
+ * @return {@code true} if the device supports hearing aid compatibility, and {@code false}
+ * otherwise.
+ */
+ public static boolean isHearingAidCompatibilitySupported(
+ @Nullable TelephonyManager telephonyManager) {
+ if (telephonyManager == null) {
+ return false;
+ }
+ if (CompatUtils.isMarshmallowCompatible()
+ || CompatUtils.isMethodAvailable(TELEPHONY_MANAGER_CLASS,
+ "isHearingAidCompatibilitySupported")) {
+ return telephonyManager.isHearingAidCompatibilitySupported();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the URI for the per-account voicemail ringtone set in Phone settings.
+ *
+ * @param telephonyManager The telephony manager instance to use for method calls.
+ * @param accountHandle The handle for the {@link android.telecom.PhoneAccount} for which to
+ * retrieve the voicemail ringtone.
+ * @return The URI for the ringtone to play when receiving a voicemail from a specific
+ * PhoneAccount.
+ */
+ @Nullable
+ public static Uri getVoicemailRingtoneUri(TelephonyManager telephonyManager,
+ PhoneAccountHandle accountHandle) {
+ if (!CompatUtils.isNCompatible()) {
+ return null;
+ }
+ return TelephonyManagerSdkCompat
+ .getVoicemailRingtoneUri(telephonyManager, accountHandle);
+ }
+
+ /**
+ * Returns whether vibration is set for voicemail notification in Phone settings.
+ *
+ * @param telephonyManager The telephony manager instance to use for method calls.
+ * @param accountHandle The handle for the {@link android.telecom.PhoneAccount} for which to
+ * retrieve the voicemail vibration setting.
+ * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise.
+ */
+ public static boolean isVoicemailVibrationEnabled(TelephonyManager telephonyManager,
+ PhoneAccountHandle accountHandle) {
+ if (!CompatUtils.isNCompatible()) {
+ return true;
+ }
+ return TelephonyManagerSdkCompat
+ .isVoicemailVibrationEnabled(telephonyManager, accountHandle);
+ }
+}
diff --git a/src/com/android/contacts/common/compat/TelephonyManagerSdkCompat.java b/src/com/android/contacts/common/compat/TelephonyManagerSdkCompat.java
new file mode 100644
index 0000000..acabfdf
--- /dev/null
+++ b/src/com/android/contacts/common/compat/TelephonyManagerSdkCompat.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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.common.compat;
+
+import android.net.Uri;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyManager;
+
+/**
+ * On N and above, this will look up voicemail notification settings from Telephony.
+ */
+public class TelephonyManagerSdkCompat {
+ public static Uri getVoicemailRingtoneUri(TelephonyManager telephonyManager,
+ PhoneAccountHandle accountHandle) {
+ return CompatUtils.isNCompatible()
+ ? telephonyManager.getVoicemailRingtoneUri(accountHandle) : null;
+ }
+
+ public static boolean isVoicemailVibrationEnabled(TelephonyManager telephonyManager,
+ PhoneAccountHandle accountHandle) {
+ return CompatUtils.isNCompatible()
+ ? telephonyManager.isVoicemailVibrationEnabled(accountHandle) : false;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/TelephonyThreadsCompat.java b/src/com/android/contacts/common/compat/TelephonyThreadsCompat.java
new file mode 100644
index 0000000..d9642c7
--- /dev/null
+++ b/src/com/android/contacts/common/compat/TelephonyThreadsCompat.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.BaseColumns;
+import android.provider.Telephony;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Patterns;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class contains static utility methods and variables extracted from Telephony and
+ * SqliteWrapper, and the methods were made visible in API level 23. In this way, we could
+ * enable the corresponding functionality for pre-M devices. We need maintain this class and keep
+ * it synced with Telephony and SqliteWrapper.
+ */
+public class TelephonyThreadsCompat {
+ /**
+ * Not instantiable.
+ */
+ private TelephonyThreadsCompat() {}
+
+ private static final String TAG = "TelephonyThreadsCompat";
+
+ public static long getOrCreateThreadId(Context context, String recipient) {
+ if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
+ return Telephony.Threads.getOrCreateThreadId(context, recipient);
+ } else {
+ return getOrCreateThreadIdInternal(context, recipient);
+ }
+ }
+
+ // Below is code copied from Telephony and SqliteWrapper
+ /**
+ * Private {@code content://} style URL for this table. Used by
+ * {@link #getOrCreateThreadId(Context, Set)}.
+ */
+ private static final Uri THREAD_ID_CONTENT_URI = Uri.parse("content://mms-sms/threadID");
+
+ private static final String[] ID_PROJECTION = { BaseColumns._ID };
+
+ /**
+ * Regex pattern for names and email addresses.
+ * <ul>
+ * <li><em>mailbox</em> = {@code name-addr}</li>
+ * <li><em>name-addr</em> = {@code [display-name] angle-addr}</li>
+ * <li><em>angle-addr</em> = {@code [CFWS] "<" addr-spec ">" [CFWS]}</li>
+ * </ul>
+ */
+ private static final Pattern NAME_ADDR_EMAIL_PATTERN =
+ Pattern.compile("\\s*(\"[^\"]*\"|[^<>\"]+)\\s*<([^<>]+)>\\s*");
+
+ /**
+ * Copied from {@link Telephony.Threads#getOrCreateThreadId(Context, String)}
+ */
+ private static long getOrCreateThreadIdInternal(Context context, String recipient) {
+ Set<String> recipients = new HashSet<String>();
+
+ recipients.add(recipient);
+ return getOrCreateThreadIdInternal(context, recipients);
+ }
+
+ /**
+ * Given the recipients list and subject of an unsaved message,
+ * return its thread ID. If the message starts a new thread,
+ * allocate a new thread ID. Otherwise, use the appropriate
+ * existing thread ID.
+ *
+ * <p>Find the thread ID of the same set of recipients (in any order,
+ * without any additions). If one is found, return it. Otherwise,
+ * return a unique thread ID.</p>
+ */
+ private static long getOrCreateThreadIdInternal(Context context, Set<String> recipients) {
+ Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon();
+
+ for (String recipient : recipients) {
+ if (isEmailAddress(recipient)) {
+ recipient = extractAddrSpec(recipient);
+ }
+
+ uriBuilder.appendQueryParameter("recipient", recipient);
+ }
+
+ Uri uri = uriBuilder.build();
+
+ Cursor cursor = query(
+ context.getContentResolver(), uri, ID_PROJECTION, null, null, null);
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ return cursor.getLong(0);
+ } else {
+ Log.e(TAG, "getOrCreateThreadId returned no rows!");
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ Log.e(TAG, "getOrCreateThreadId failed with uri " + uri.toString());
+ throw new IllegalArgumentException("Unable to find or allocate a thread ID.");
+ }
+
+ /**
+ * Copied from {@link SqliteWrapper#query}
+ */
+ private static Cursor query(ContentResolver resolver, Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder) {
+ try {
+ return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
+ } catch (Exception e) {
+ Log.e(TAG, "Catch an exception when query: ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Is the specified address an email address?
+ *
+ * @param address the input address to test
+ * @return true if address is an email address; false otherwise.
+ */
+ private static boolean isEmailAddress(String address) {
+ if (TextUtils.isEmpty(address)) {
+ return false;
+ }
+
+ String s = extractAddrSpec(address);
+ Matcher match = Patterns.EMAIL_ADDRESS.matcher(s);
+ return match.matches();
+ }
+
+ /**
+ * Helper method to extract email address from address string.
+ */
+ private static String extractAddrSpec(String address) {
+ Matcher match = NAME_ADDR_EMAIL_PATTERN.matcher(address);
+
+ if (match.matches()) {
+ return match.group(2);
+ }
+ return address;
+ }
+}
diff --git a/src/com/android/contacts/common/compat/telecom/TelecomManagerCompat.java b/src/com/android/contacts/common/compat/telecom/TelecomManagerCompat.java
new file mode 100644
index 0000000..6292b7f
--- /dev/null
+++ b/src/com/android/contacts/common/compat/telecom/TelecomManagerCompat.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2015 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.common.compat.telecom;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.Context;
+import android.net.Uri;
+import android.support.annotation.Nullable;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import com.android.contacts.common.compat.CompatUtils;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Compatibility class for {@link android.telecom.TelecomManager}.
+ */
+public class TelecomManagerCompat {
+ public static final String TELECOM_MANAGER_CLASS = "android.telecom.TelecomManager";
+ /**
+ * Places a new outgoing call to the provided address using the system telecom service with
+ * the specified intent.
+ *
+ * @param activity {@link Activity} used to start another activity for the given intent
+ * @param telecomManager the {@link TelecomManager} used to place a call, if possible
+ * @param intent the intent for the call
+ */
+ public static void placeCall(@Nullable Activity activity,
+ @Nullable TelecomManager telecomManager, @Nullable Intent intent) {
+ if (activity == null || telecomManager == null || intent == null) {
+ return;
+ }
+ if (CompatUtils.isMarshmallowCompatible()) {
+ telecomManager.placeCall(intent.getData(), intent.getExtras());
+ return;
+ }
+ activity.startActivityForResult(intent, 0);
+ }
+
+ /**
+ * Get the URI for running an adn query.
+ *
+ * @param telecomManager the {@link TelecomManager} used for method calls, if possible.
+ * @param accountHandle The handle for the account to derive an adn query URI for or
+ * {@code null} to return a URI which will use the default account.
+ * @return The URI (with the content:// scheme) specific to the specified {@link PhoneAccount}
+ * for the the content retrieve.
+ */
+ public static Uri getAdnUriForPhoneAccount(@Nullable TelecomManager telecomManager,
+ PhoneAccountHandle accountHandle) {
+ if (telecomManager != null && (CompatUtils.isMarshmallowCompatible()
+ || CompatUtils.isMethodAvailable(TELECOM_MANAGER_CLASS, "getAdnUriForPhoneAccount",
+ PhoneAccountHandle.class))) {
+ return telecomManager.getAdnUriForPhoneAccount(accountHandle);
+ }
+ return Uri.parse("content://icc/adn");
+ }
+
+ /**
+ * Returns a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
+ * calls. The returned list includes only those accounts which have been explicitly enabled
+ * by the user.
+ *
+ * @param telecomManager the {@link TelecomManager} used for method calls, if possible.
+ * @return A list of PhoneAccountHandle objects.
+ */
+ public static List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+ @Nullable TelecomManager telecomManager) {
+ if (telecomManager != null && (CompatUtils.isMarshmallowCompatible()
+ || CompatUtils.isMethodAvailable(TELECOM_MANAGER_CLASS,
+ "getCallCapablePhoneAccounts"))) {
+ return telecomManager.getCallCapablePhoneAccounts();
+ }
+ return new ArrayList<>();
+ }
+
+ /**
+ * Used to determine the currently selected default dialer package.
+ *
+ * @param telecomManager the {@link TelecomManager} used for method calls, if possible.
+ * @return package name for the default dialer package or null if no package has been
+ * selected as the default dialer.
+ */
+ @Nullable
+ public static String getDefaultDialerPackage(@Nullable TelecomManager telecomManager) {
+ if (telecomManager != null && CompatUtils.isDefaultDialerCompatible()) {
+ return telecomManager.getDefaultDialerPackage();
+ }
+ return null;
+ }
+
+ /**
+ * Return the {@link PhoneAccount} which will be used to place outgoing calls to addresses with
+ * the specified {@code uriScheme}. This PhoneAccount will always be a member of the
+ * list which is returned from invoking {@link TelecomManager#getCallCapablePhoneAccounts()}.
+ * The specific account returned depends on the following priorities:
+ *
+ * 1. If the user-selected default PhoneAccount supports the specified scheme, it will
+ * be returned.
+ * 2. If there exists only one PhoneAccount that supports the specified scheme, it
+ * will be returned.
+ *
+ * If no PhoneAccount fits the criteria above, this method will return {@code null}.
+ *
+ * @param telecomManager the {@link TelecomManager} used for method calls, if possible.
+ * @param uriScheme The URI scheme.
+ * @return The {@link PhoneAccountHandle} corresponding to the account to be used.
+ */
+ @Nullable
+ public static PhoneAccountHandle getDefaultOutgoingPhoneAccount(
+ @Nullable TelecomManager telecomManager, @Nullable String uriScheme) {
+ if (telecomManager != null && (CompatUtils.isMarshmallowCompatible()
+ || CompatUtils.isMethodAvailable(TELECOM_MANAGER_CLASS,
+ "getDefaultOutgoingPhoneAccount", String.class))) {
+ return telecomManager.getDefaultOutgoingPhoneAccount(uriScheme);
+ }
+ return null;
+ }
+
+ /**
+ * Return the line 1 phone number for given phone account.
+ *
+ * @param telecomManager the {@link TelecomManager} to use in the event that
+ * {@link TelecomManager#getLine1Number(PhoneAccountHandle)} is available
+ * @param telephonyManager the {@link TelephonyManager} to use if TelecomManager#getLine1Number
+ * is unavailable
+ * @param phoneAccountHandle the phoneAccountHandle upon which to check the line one number
+ * @return the line one number
+ */
+ @Nullable
+ public static String getLine1Number(@Nullable TelecomManager telecomManager,
+ @Nullable TelephonyManager telephonyManager,
+ @Nullable PhoneAccountHandle phoneAccountHandle) {
+ if (telecomManager != null && CompatUtils.isMarshmallowCompatible()) {
+ return telecomManager.getLine1Number(phoneAccountHandle);
+ }
+ if (telephonyManager != null) {
+ return telephonyManager.getLine1Number();
+ }
+ return null;
+ }
+
+ /**
+ * Return whether a given phone number is the configured voicemail number for a
+ * particular phone account.
+ *
+ * @param telecomManager the {@link TelecomManager} to use for checking the number.
+ * @param accountHandle The handle for the account to check the voicemail number against
+ * @param number The number to look up.
+ */
+ public static boolean isVoiceMailNumber(@Nullable TelecomManager telecomManager,
+ @Nullable PhoneAccountHandle accountHandle, @Nullable String number) {
+ if (telecomManager != null && (CompatUtils.isMarshmallowCompatible()
+ || CompatUtils.isMethodAvailable(TELECOM_MANAGER_CLASS, "isVoiceMailNumber",
+ PhoneAccountHandle.class, String.class))) {
+ return telecomManager.isVoiceMailNumber(accountHandle, number);
+ }
+ return PhoneNumberUtils.isVoiceMailNumber(number);
+ }
+
+ /**
+ * Return the {@link PhoneAccount} for a specified {@link PhoneAccountHandle}. Object includes
+ * resources which can be used in a user interface.
+ *
+ * @param telecomManager the {@link TelecomManager} used for method calls, if possible.
+ * @param account The {@link PhoneAccountHandle}.
+ * @return The {@link PhoneAccount} object or null if it doesn't exist.
+ */
+ @Nullable
+ public static PhoneAccount getPhoneAccount(@Nullable TelecomManager telecomManager,
+ @Nullable PhoneAccountHandle accountHandle) {
+ if (telecomManager != null && (CompatUtils.isMethodAvailable(
+ TELECOM_MANAGER_CLASS, "getPhoneAccount", PhoneAccountHandle.class))) {
+ return telecomManager.getPhoneAccount(accountHandle);
+ }
+ return null;
+ }
+
+ /**
+ * Return the voicemail number for a given phone account.
+ *
+ * @param telecomManager The {@link TelecomManager} object to use for retrieving the voicemail
+ * number if accountHandle is specified.
+ * @param telephonyManager The {@link TelephonyManager} object to use for retrieving the
+ * voicemail number if accountHandle is null.
+ * @param accountHandle The handle for the phone account.
+ * @return The voicemail number for the phone account, and {@code null} if one has not been
+ * configured.
+ */
+ @Nullable
+ public static String getVoiceMailNumber(@Nullable TelecomManager telecomManager,
+ @Nullable TelephonyManager telephonyManager,
+ @Nullable PhoneAccountHandle accountHandle) {
+ if (telecomManager != null && (CompatUtils.isMethodAvailable(
+ TELECOM_MANAGER_CLASS, "getVoiceMailNumber", PhoneAccountHandle.class))) {
+ return telecomManager.getVoiceMailNumber(accountHandle);
+ } else if (telephonyManager != null){
+ return telephonyManager.getVoiceMailNumber();
+ }
+ return null;
+ }
+
+ /**
+ * Processes the specified dial string as an MMI code.
+ * MMI codes are any sequence of characters entered into the dialpad that contain a "*" or "#".
+ * Some of these sequences launch special behavior through handled by Telephony.
+ *
+ * @param telecomManager The {@link TelecomManager} object to use for handling MMI.
+ * @param dialString The digits to dial.
+ * @return {@code true} if the digits were processed as an MMI code, {@code false} otherwise.
+ */
+ public static boolean handleMmi(@Nullable TelecomManager telecomManager,
+ @Nullable String dialString, @Nullable PhoneAccountHandle accountHandle) {
+ if (telecomManager == null || TextUtils.isEmpty(dialString)) {
+ return false;
+ }
+ if (CompatUtils.isMarshmallowCompatible()) {
+ return telecomManager.handleMmi(dialString, accountHandle);
+ }
+
+ Object handleMmiResult = CompatUtils.invokeMethod(
+ telecomManager,
+ "handleMmi",
+ new Class<?>[] {PhoneAccountHandle.class, String.class},
+ new Object[] {accountHandle, dialString});
+ if (handleMmiResult != null) {
+ return (boolean) handleMmiResult;
+ }
+
+ return telecomManager.handleMmi(dialString);
+ }
+
+ /**
+ * Silences the ringer if a ringing call exists. Noop if {@link TelecomManager#silenceRinger()}
+ * is unavailable.
+ *
+ * @param telecomManager the TelecomManager to use to silence the ringer.
+ */
+ public static void silenceRinger(@Nullable TelecomManager telecomManager) {
+ if (telecomManager != null && (CompatUtils.isMarshmallowCompatible() || CompatUtils
+ .isMethodAvailable(TELECOM_MANAGER_CLASS, "silenceRinger"))) {
+ telecomManager.silenceRinger();
+ }
+ }
+
+ /**
+ * Returns the current SIM call manager. Apps must be prepared for this method to return null,
+ * indicating that there currently exists no registered SIM call manager.
+ *
+ * @param telecomManager the {@link TelecomManager} to use to fetch the SIM call manager.
+ * @return The phone account handle of the current sim call manager.
+ */
+ @Nullable
+ public static PhoneAccountHandle getSimCallManager(TelecomManager telecomManager) {
+ if (telecomManager != null && (CompatUtils.isMarshmallowCompatible() || CompatUtils
+ .isMethodAvailable(TELECOM_MANAGER_CLASS, "getSimCallManager"))) {
+ return telecomManager.getSimCallManager();
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/contacts/common/database/ContactUpdateUtils.java b/src/com/android/contacts/common/database/ContactUpdateUtils.java
new file mode 100644
index 0000000..1bd08aa
--- /dev/null
+++ b/src/com/android/contacts/common/database/ContactUpdateUtils.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 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.common.database;
+
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract;
+import android.util.Log;
+
+/**
+ * Static methods to update contact information.
+ */
+public class ContactUpdateUtils {
+
+ private static final String TAG = ContactUpdateUtils.class.getSimpleName();
+
+ public static void setSuperPrimary(Context context, long dataId) {
+ if (dataId == -1) {
+ Log.e(TAG, "Invalid arguments for setSuperPrimary request");
+ return;
+ }
+
+ // Update the primary values in the data record.
+ ContentValues values = new ContentValues(2);
+ values.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
+ values.put(ContactsContract.Data.IS_PRIMARY, 1);
+
+ context.getContentResolver().update(
+ ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, dataId),
+ values, null, null);
+ }
+}
diff --git a/src/com/android/contacts/common/database/EmptyCursor.java b/src/com/android/contacts/common/database/EmptyCursor.java
new file mode 100644
index 0000000..ad00eff
--- /dev/null
+++ b/src/com/android/contacts/common/database/EmptyCursor.java
@@ -0,0 +1,84 @@
+/*
+* Copyright (C) 2012 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.common.database;
+
+import android.database.AbstractCursor;
+import android.database.CursorIndexOutOfBoundsException;
+
+/**
+ * A cursor that is empty.
+ * <p>
+ * If you want an empty cursor, this class is better than a MatrixCursor because it has less
+ * overhead.
+ */
+final public class EmptyCursor extends AbstractCursor {
+
+ private String[] mColumns;
+
+ public EmptyCursor(String[] columns) {
+ this.mColumns = columns;
+ }
+
+ @Override
+ public int getCount() {
+ return 0;
+ }
+
+ @Override
+ public String[] getColumnNames() {
+ return mColumns;
+ }
+
+ @Override
+ public String getString(int column) {
+ throw cursorException();
+ }
+
+ @Override
+ public short getShort(int column) {
+ throw cursorException();
+ }
+
+ @Override
+ public int getInt(int column) {
+ throw cursorException();
+ }
+
+ @Override
+ public long getLong(int column) {
+ throw cursorException();
+ }
+
+ @Override
+ public float getFloat(int column) {
+ throw cursorException();
+ }
+
+ @Override
+ public double getDouble(int column) {
+ throw cursorException();
+ }
+
+ @Override
+ public boolean isNull(int column) {
+ throw cursorException();
+ }
+
+ private CursorIndexOutOfBoundsException cursorException() {
+ return new CursorIndexOutOfBoundsException("Operation not permitted on an empty cursor.");
+ }
+}
diff --git a/src/com/android/contacts/common/database/NoNullCursorAsyncQueryHandler.java b/src/com/android/contacts/common/database/NoNullCursorAsyncQueryHandler.java
new file mode 100644
index 0000000..aefc0fd
--- /dev/null
+++ b/src/com/android/contacts/common/database/NoNullCursorAsyncQueryHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 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.common.database;
+
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * An {@AsyncQueryHandler} that will never return a null cursor.
+ * <p>
+ * Instead, will return a {@link Cursor} with 0 records.
+ */
+public abstract class NoNullCursorAsyncQueryHandler extends AsyncQueryHandler {
+
+ public NoNullCursorAsyncQueryHandler(ContentResolver cr) {
+ super(cr);
+ }
+
+ @Override
+ public void startQuery(int token, Object cookie, Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String orderBy) {
+ final CookieWithProjection projectionCookie = new CookieWithProjection(cookie, projection);
+ super.startQuery(token, projectionCookie, uri, projection, selection, selectionArgs,
+ orderBy);
+ }
+
+ @Override
+ protected final void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ CookieWithProjection projectionCookie = (CookieWithProjection) cookie;
+
+ super.onQueryComplete(token, projectionCookie.originalCookie, cursor);
+
+ if (cursor == null) {
+ cursor = new EmptyCursor(projectionCookie.projection);
+ }
+ onNotNullableQueryComplete(token, projectionCookie.originalCookie, cursor);
+ }
+
+ protected abstract void onNotNullableQueryComplete(int token, Object cookie, Cursor cursor);
+
+ /**
+ * Class to add projection to an existing cookie.
+ */
+ private static class CookieWithProjection {
+ public final Object originalCookie;
+ public final String[] projection;
+
+ public CookieWithProjection(Object cookie, String[] projection) {
+ this.originalCookie = cookie;
+ this.projection = projection;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/dialog/CallSubjectDialog.java b/src/com/android/contacts/common/dialog/CallSubjectDialog.java
new file mode 100644
index 0000000..a17c4fc
--- /dev/null
+++ b/src/com/android/contacts/common/dialog/CallSubjectDialog.java
@@ -0,0 +1,623 @@
+/*
+ * Copyright (C) 2015 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.common.dialog;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.QuickContactBadge;
+import android.widget.TextView;
+
+import com.android.contacts.common.CallUtil;
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.PhoneAccountSdkCompat;
+import com.android.contacts.common.compat.telecom.TelecomManagerCompat;
+import com.android.contacts.common.util.UriUtils;
+import com.android.phone.common.animation.AnimUtils;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implements a dialog which prompts for a call subject for an outgoing call. The dialog includes
+ * a pop up list of historical call subjects.
+ */
+public class CallSubjectDialog extends Activity {
+ private static final String TAG = "CallSubjectDialog";
+ private static final int CALL_SUBJECT_LIMIT = 16;
+ private static final int CALL_SUBJECT_HISTORY_SIZE = 5;
+
+ private static final int REQUEST_SUBJECT = 1001;
+
+ public static final String PREF_KEY_SUBJECT_HISTORY_COUNT = "subject_history_count";
+ public static final String PREF_KEY_SUBJECT_HISTORY_ITEM = "subject_history_item";
+
+ /**
+ * Activity intent argument bundle keys:
+ */
+ public static final String ARG_PHOTO_ID = "PHOTO_ID";
+ public static final String ARG_PHOTO_URI = "PHOTO_URI";
+ public static final String ARG_CONTACT_URI = "CONTACT_URI";
+ public static final String ARG_NAME_OR_NUMBER = "NAME_OR_NUMBER";
+ public static final String ARG_IS_BUSINESS = "IS_BUSINESS";
+ public static final String ARG_NUMBER = "NUMBER";
+ public static final String ARG_DISPLAY_NUMBER = "DISPLAY_NUMBER";
+ public static final String ARG_NUMBER_LABEL = "NUMBER_LABEL";
+ public static final String ARG_PHONE_ACCOUNT_HANDLE = "PHONE_ACCOUNT_HANDLE";
+
+ private int mAnimationDuration;
+ private Charset mMessageEncoding;
+ private View mBackgroundView;
+ private View mDialogView;
+ private QuickContactBadge mContactPhoto;
+ private TextView mNameView;
+ private TextView mNumberView;
+ private EditText mCallSubjectView;
+ private TextView mCharacterLimitView;
+ private View mHistoryButton;
+ private View mSendAndCallButton;
+ private ListView mSubjectList;
+
+ private int mLimit = CALL_SUBJECT_LIMIT;
+ private int mPhotoSize;
+ private SharedPreferences mPrefs;
+ private List<String> mSubjectHistory;
+
+ private long mPhotoID;
+ private Uri mPhotoUri;
+ private Uri mContactUri;
+ private String mNameOrNumber;
+ private boolean mIsBusiness;
+ private String mNumber;
+ private String mDisplayNumber;
+ private String mNumberLabel;
+ private PhoneAccountHandle mPhoneAccountHandle;
+
+ /**
+ * Handles changes to the text in the subject box. Ensures the character limit is updated.
+ */
+ private final TextWatcher mTextWatcher = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // no-op
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ updateCharacterLimit();
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ // no-op
+ }
+ };
+
+ /**
+ * Click listener which handles user clicks outside of the dialog.
+ */
+ private View.OnClickListener mBackgroundListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ finish();
+ }
+ };
+
+ /**
+ * Handles displaying the list of past call subjects.
+ */
+ private final View.OnClickListener mHistoryOnClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ hideSoftKeyboard(CallSubjectDialog.this, mCallSubjectView);
+ showCallHistory(mSubjectList.getVisibility() == View.GONE);
+ }
+ };
+
+ /**
+ * Handles starting a call with a call subject specified.
+ */
+ private final View.OnClickListener mSendAndCallOnClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ String subject = mCallSubjectView.getText().toString();
+ Intent intent = CallUtil.getCallWithSubjectIntent(mNumber, mPhoneAccountHandle,
+ subject);
+
+ TelecomManagerCompat.placeCall(
+ CallSubjectDialog.this,
+ (TelecomManager) getSystemService(Context.TELECOM_SERVICE),
+ intent);
+
+ mSubjectHistory.add(subject);
+ saveSubjectHistory(mSubjectHistory);
+ finish();
+ }
+ };
+
+ /**
+ * Handles auto-hiding the call history when user clicks in the call subject field to give it
+ * focus.
+ */
+ private final View.OnClickListener mCallSubjectClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mSubjectList.getVisibility() == View.VISIBLE) {
+ showCallHistory(false);
+ }
+ }
+ };
+
+ /**
+ * Item click listener which handles user clicks on the items in the list view. Dismisses
+ * the activity, returning the subject to the caller and closing the activity with the
+ * {@link Activity#RESULT_OK} result code.
+ */
+ private AdapterView.OnItemClickListener mItemClickListener =
+ new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
+ mCallSubjectView.setText(mSubjectHistory.get(position));
+ showCallHistory(false);
+ }
+ };
+
+ /**
+ * Show the call subject dialog given a phone number to dial (e.g. from the dialpad).
+ *
+ * @param activity The activity.
+ * @param number The number to dial.
+ */
+ public static void start(Activity activity, String number) {
+ start(activity,
+ -1 /* photoId */,
+ null /* photoUri */,
+ null /* contactUri */,
+ number /* nameOrNumber */,
+ false /* isBusiness */,
+ number /* number */,
+ null /* displayNumber */,
+ null /* numberLabel */,
+ null /* phoneAccountHandle */);
+ }
+
+ /**
+ * Creates a call subject dialog.
+ *
+ * @param activity The current activity.
+ * @param photoId The photo ID (used to populate contact photo).
+ * @param photoUri The photo Uri (used to populate contact photo).
+ * @param contactUri The Contact URI (used so quick contact can be invoked from contact photo).
+ * @param nameOrNumber The name or number of the callee.
+ * @param isBusiness {@code true} if a business is being called (used for contact photo).
+ * @param number The raw number to dial.
+ * @param displayNumber The number to dial, formatted for display.
+ * @param numberLabel The label for the number (if from a contact).
+ * @param phoneAccountHandle The phone account handle.
+ */
+ public static void start(Activity activity, long photoId, Uri photoUri, Uri contactUri,
+ String nameOrNumber, boolean isBusiness, String number, String displayNumber,
+ String numberLabel, PhoneAccountHandle phoneAccountHandle) {
+ Bundle arguments = new Bundle();
+ arguments.putLong(ARG_PHOTO_ID, photoId);
+ arguments.putParcelable(ARG_PHOTO_URI, photoUri);
+ arguments.putParcelable(ARG_CONTACT_URI, contactUri);
+ arguments.putString(ARG_NAME_OR_NUMBER, nameOrNumber);
+ arguments.putBoolean(ARG_IS_BUSINESS, isBusiness);
+ arguments.putString(ARG_NUMBER, number);
+ arguments.putString(ARG_DISPLAY_NUMBER, displayNumber);
+ arguments.putString(ARG_NUMBER_LABEL, numberLabel);
+ arguments.putParcelable(ARG_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
+ start(activity, arguments);
+ }
+
+ /**
+ * Shows the call subject dialog given a Bundle containing all the arguments required to
+ * display the dialog (e.g. from Quick Contacts).
+ *
+ * @param activity The activity.
+ * @param arguments The arguments bundle.
+ */
+ public static void start(Activity activity, Bundle arguments) {
+ Intent intent = new Intent(activity, CallSubjectDialog.class);
+ intent.putExtras(arguments);
+ activity.startActivity(intent);
+ }
+
+ /**
+ * Creates the dialog, inflating the layout and populating it with the name and phone number.
+ *
+ * @param savedInstanceState The last saved instance state of the Fragment,
+ * or null if this is a freshly created Fragment.
+ *
+ * @return Dialog instance.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mAnimationDuration = getResources().getInteger(R.integer.call_subject_animation_duration);
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ mPhotoSize = getResources().getDimensionPixelSize(
+ R.dimen.call_subject_dialog_contact_photo_size);
+ readArguments();
+ loadConfiguration();
+ mSubjectHistory = loadSubjectHistory(mPrefs);
+
+ setContentView(R.layout.dialog_call_subject);
+ getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mBackgroundView = findViewById(R.id.call_subject_dialog);
+ mBackgroundView.setOnClickListener(mBackgroundListener);
+ mDialogView = findViewById(R.id.dialog_view);
+ mContactPhoto = (QuickContactBadge) findViewById(R.id.contact_photo);
+ mNameView = (TextView) findViewById(R.id.name);
+ mNumberView = (TextView) findViewById(R.id.number);
+ mCallSubjectView = (EditText) findViewById(R.id.call_subject);
+ mCallSubjectView.addTextChangedListener(mTextWatcher);
+ mCallSubjectView.setOnClickListener(mCallSubjectClickListener);
+ InputFilter[] filters = new InputFilter[1];
+ filters[0] = new InputFilter.LengthFilter(mLimit);
+ mCallSubjectView.setFilters(filters);
+ mCharacterLimitView = (TextView) findViewById(R.id.character_limit);
+ mHistoryButton = findViewById(R.id.history_button);
+ mHistoryButton.setOnClickListener(mHistoryOnClickListener);
+ mHistoryButton.setVisibility(mSubjectHistory.isEmpty() ? View.GONE : View.VISIBLE);
+ mSendAndCallButton = findViewById(R.id.send_and_call_button);
+ mSendAndCallButton.setOnClickListener(mSendAndCallOnClickListener);
+ mSubjectList = (ListView) findViewById(R.id.subject_list);
+ mSubjectList.setOnItemClickListener(mItemClickListener);
+ mSubjectList.setVisibility(View.GONE);
+
+ updateContactInfo();
+ updateCharacterLimit();
+ }
+
+ /**
+ * Populates the contact info fields based on the current contact information.
+ */
+ private void updateContactInfo() {
+ if (mContactUri != null) {
+ setPhoto(mPhotoID, mPhotoUri, mContactUri, mNameOrNumber, mIsBusiness);
+ } else {
+ mContactPhoto.setVisibility(View.GONE);
+ }
+ mNameView.setText(mNameOrNumber);
+ if (!TextUtils.isEmpty(mNumberLabel) && !TextUtils.isEmpty(mDisplayNumber)) {
+ mNumberView.setVisibility(View.VISIBLE);
+ mNumberView.setText(getString(R.string.call_subject_type_and_number,
+ mNumberLabel, mDisplayNumber));
+ } else {
+ mNumberView.setVisibility(View.GONE);
+ mNumberView.setText(null);
+ }
+ }
+
+ /**
+ * Reads arguments from the fragment arguments and populates the necessary instance variables.
+ */
+ private void readArguments() {
+ Bundle arguments = getIntent().getExtras();
+ if (arguments == null) {
+ Log.e(TAG, "Arguments cannot be null.");
+ return;
+ }
+ mPhotoID = arguments.getLong(ARG_PHOTO_ID);
+ mPhotoUri = arguments.getParcelable(ARG_PHOTO_URI);
+ mContactUri = arguments.getParcelable(ARG_CONTACT_URI);
+ mNameOrNumber = arguments.getString(ARG_NAME_OR_NUMBER);
+ mIsBusiness = arguments.getBoolean(ARG_IS_BUSINESS);
+ mNumber = arguments.getString(ARG_NUMBER);
+ mDisplayNumber = arguments.getString(ARG_DISPLAY_NUMBER);
+ mNumberLabel = arguments.getString(ARG_NUMBER_LABEL);
+ mPhoneAccountHandle = arguments.getParcelable(ARG_PHONE_ACCOUNT_HANDLE);
+ }
+
+ /**
+ * Updates the character limit display, coloring the text RED when the limit is reached or
+ * exceeded.
+ */
+ private void updateCharacterLimit() {
+ String subjectText = mCallSubjectView.getText().toString();
+ final int length;
+
+ // If a message encoding is specified, use that to count bytes in the message.
+ if (mMessageEncoding != null) {
+ length = subjectText.getBytes(mMessageEncoding).length;
+ } else {
+ // No message encoding specified, so just count characters entered.
+ length = subjectText.length();
+ }
+
+ mCharacterLimitView.setText(
+ getString(R.string.call_subject_limit, length, mLimit));
+ if (length >= mLimit) {
+ mCharacterLimitView.setTextColor(getResources().getColor(
+ R.color.call_subject_limit_exceeded));
+ } else {
+ mCharacterLimitView.setTextColor(getResources().getColor(
+ R.color.dialtacts_secondary_text_color));
+ }
+ }
+
+ /**
+ * Sets the photo on the quick contact photo.
+ *
+ * @param photoId
+ * @param photoUri
+ * @param contactUri
+ * @param displayName
+ * @param isBusiness
+ */
+ private void setPhoto(long photoId, Uri photoUri, Uri contactUri, String displayName,
+ boolean isBusiness) {
+ mContactPhoto.assignContactUri(contactUri);
+ if (CompatUtils.isLollipopCompatible()) {
+ mContactPhoto.setOverlay(null);
+ }
+
+ int contactType;
+ if (isBusiness) {
+ contactType = ContactPhotoManager.TYPE_BUSINESS;
+ } else {
+ contactType = ContactPhotoManager.TYPE_DEFAULT;
+ }
+
+ String lookupKey = null;
+ if (contactUri != null) {
+ lookupKey = UriUtils.getLookupKeyFromUri(contactUri);
+ }
+
+ ContactPhotoManager.DefaultImageRequest
+ request = new ContactPhotoManager.DefaultImageRequest(
+ displayName, lookupKey, contactType, true /* isCircular */);
+
+ if (photoId == 0 && photoUri != null) {
+ ContactPhotoManager.getInstance(this).loadPhoto(mContactPhoto, photoUri,
+ mPhotoSize, false /* darkTheme */, true /* isCircular */, request);
+ } else {
+ ContactPhotoManager.getInstance(this).loadThumbnail(mContactPhoto, photoId,
+ false /* darkTheme */, true /* isCircular */, request);
+ }
+ }
+
+ /**
+ * Loads the subject history from shared preferences.
+ *
+ * @param prefs Shared preferences.
+ * @return List of subject history strings.
+ */
+ public static List<String> loadSubjectHistory(SharedPreferences prefs) {
+ int historySize = prefs.getInt(PREF_KEY_SUBJECT_HISTORY_COUNT, 0);
+ List<String> subjects = new ArrayList(historySize);
+
+ for (int ix = 0 ; ix < historySize; ix++) {
+ String historyItem = prefs.getString(PREF_KEY_SUBJECT_HISTORY_ITEM + ix, null);
+ if (!TextUtils.isEmpty(historyItem)) {
+ subjects.add(historyItem);
+ }
+ }
+
+ return subjects;
+ }
+
+ /**
+ * Saves the subject history list to shared prefs, removing older items so that there are only
+ * {@link #CALL_SUBJECT_HISTORY_SIZE} items at most.
+ *
+ * @param history The history.
+ */
+ private void saveSubjectHistory(List<String> history) {
+ // Remove oldest subject(s).
+ while (history.size() > CALL_SUBJECT_HISTORY_SIZE) {
+ history.remove(0);
+ }
+
+ SharedPreferences.Editor editor = mPrefs.edit();
+ int historyCount = 0;
+ for (String subject : history) {
+ if (!TextUtils.isEmpty(subject)) {
+ editor.putString(PREF_KEY_SUBJECT_HISTORY_ITEM + historyCount,
+ subject);
+ historyCount++;
+ }
+ }
+ editor.putInt(PREF_KEY_SUBJECT_HISTORY_COUNT, historyCount);
+ editor.apply();
+ }
+
+ /**
+ * Hide software keyboard for the given {@link View}.
+ */
+ public void hideSoftKeyboard(Context context, View view) {
+ InputMethodManager imm = (InputMethodManager) context.getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+ }
+ }
+
+ /**
+ * Hides or shows the call history list.
+ *
+ * @param show {@code true} if the call history should be shown, {@code false} otherwise.
+ */
+ private void showCallHistory(final boolean show) {
+ // Bail early if the visibility has not changed.
+ if ((show && mSubjectList.getVisibility() == View.VISIBLE) ||
+ (!show && mSubjectList.getVisibility() == View.GONE)) {
+ return;
+ }
+
+ final int dialogStartingBottom = mDialogView.getBottom();
+ if (show) {
+ // Showing the subject list; bind the list of history items to the list and show it.
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(CallSubjectDialog.this,
+ R.layout.call_subject_history_list_item, mSubjectHistory);
+ mSubjectList.setAdapter(adapter);
+ mSubjectList.setVisibility(View.VISIBLE);
+ } else {
+ // Hiding the subject list.
+ mSubjectList.setVisibility(View.GONE);
+ }
+
+ // Use a ViewTreeObserver so that we can animate between the pre-layout and post-layout
+ // states.
+ final ViewTreeObserver observer = mBackgroundView.getViewTreeObserver();
+ observer.addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ // We don't want to continue getting called.
+ if (observer.isAlive()) {
+ observer.removeOnPreDrawListener(this);
+ }
+
+ // Determine the amount the dialog has shifted due to the relayout.
+ int shiftAmount = dialogStartingBottom - mDialogView.getBottom();
+
+ // If the dialog needs to be shifted, do that now.
+ if (shiftAmount != 0) {
+ // Start animation in translated state and animate to translationY 0.
+ mDialogView.setTranslationY(shiftAmount);
+ mDialogView.animate()
+ .translationY(0)
+ .setInterpolator(AnimUtils.EASE_OUT_EASE_IN)
+ .setDuration(mAnimationDuration)
+ .start();
+ }
+
+ if (show) {
+ // Show the subhect list.
+ mSubjectList.setTranslationY(mSubjectList.getHeight());
+
+ mSubjectList.animate()
+ .translationY(0)
+ .setInterpolator(AnimUtils.EASE_OUT_EASE_IN)
+ .setDuration(mAnimationDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mSubjectList.setVisibility(View.VISIBLE);
+ }
+ })
+ .start();
+ } else {
+ // Hide the subject list.
+ mSubjectList.setTranslationY(0);
+
+ mSubjectList.animate()
+ .translationY(mSubjectList.getHeight())
+ .setInterpolator(AnimUtils.EASE_OUT_EASE_IN)
+ .setDuration(mAnimationDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mSubjectList.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ }
+ })
+ .start();
+ }
+ return true;
+ }
+ }
+ );
+ }
+
+ /**
+ * Loads the message encoding and maximum message length from the phone account extras for the
+ * current phone account.
+ */
+ private void loadConfiguration() {
+ // Only attempt to load configuration from the phone account extras if the SDK is N or
+ // later. If we've got a prior SDK the default encoding and message length will suffice.
+ int sdk = android.os.Build.VERSION.SDK_INT;
+ if(sdk <= android.os.Build.VERSION_CODES.M) {
+ return;
+ }
+
+ if (mPhoneAccountHandle == null) {
+ return;
+ }
+
+ TelecomManager telecomManager =
+ (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
+ final PhoneAccount account = telecomManager.getPhoneAccount(mPhoneAccountHandle);
+
+ Bundle phoneAccountExtras = PhoneAccountSdkCompat.getExtras(account);
+ if (phoneAccountExtras == null) {
+ return;
+ }
+
+ // Get limit, if provided; otherwise default to existing value.
+ mLimit = phoneAccountExtras
+ .getInt(PhoneAccountSdkCompat.EXTRA_CALL_SUBJECT_MAX_LENGTH, mLimit);
+
+ // Get charset; default to none (e.g. count characters 1:1).
+ String charsetName = phoneAccountExtras.getString(
+ PhoneAccountSdkCompat.EXTRA_CALL_SUBJECT_CHARACTER_ENCODING);
+
+ if (!TextUtils.isEmpty(charsetName)) {
+ try {
+ mMessageEncoding = Charset.forName(charsetName);
+ } catch (java.nio.charset.UnsupportedCharsetException uce) {
+ // Character set was invalid; log warning and fallback to none.
+ Log.w(TAG, "Invalid charset: " + charsetName);
+ mMessageEncoding = null;
+ }
+ } else {
+ // No character set specified, so count characters 1:1.
+ mMessageEncoding = null;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/dialog/ClearFrequentsDialog.java b/src/com/android/contacts/common/dialog/ClearFrequentsDialog.java
new file mode 100644
index 0000000..2fab3e1
--- /dev/null
+++ b/src/com/android/contacts/common/dialog/ClearFrequentsDialog.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 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.common.dialog;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.util.PermissionsUtil;
+
+/**
+ * Dialog that clears the frequently contacted list after confirming with the user.
+ */
+public class ClearFrequentsDialog extends DialogFragment {
+ /** Preferred way to show this dialog */
+ public static void show(FragmentManager fragmentManager) {
+ ClearFrequentsDialog dialog = new ClearFrequentsDialog();
+ dialog.show(fragmentManager, "clearFrequents");
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity().getApplicationContext();
+ final ContentResolver resolver = getActivity().getContentResolver();
+ final OnClickListener okListener = new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (!PermissionsUtil.hasContactsPermissions(context)) {
+ return;
+ }
+ final IndeterminateProgressDialog progressDialog = IndeterminateProgressDialog.show(
+ getFragmentManager(), getString(R.string.clearFrequentsProgress_title),
+ null, 500);
+ final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ resolver.delete(ContactsContract.DataUsageFeedback.DELETE_USAGE_URI,
+ null, null);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ progressDialog.dismiss();
+ }
+ };
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ };
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.clearFrequentsConfirmation_title)
+ .setMessage(R.string.clearFrequentsConfirmation)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, okListener)
+ .setCancelable(true)
+ .create();
+ }
+}
diff --git a/src/com/android/contacts/common/dialog/IndeterminateProgressDialog.java b/src/com/android/contacts/common/dialog/IndeterminateProgressDialog.java
new file mode 100644
index 0000000..2fe059f
--- /dev/null
+++ b/src/com/android/contacts/common/dialog/IndeterminateProgressDialog.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2012 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.common.dialog;
+
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.Handler;
+
+/**
+ * Indeterminate progress dialog wrapped up in a DialogFragment to work even when the device
+ * orientation is changed. Currently, only supports adding a title and/or message to the progress
+ * dialog. There is an additional parameter of the minimum amount of time to display the progress
+ * dialog even after a call to dismiss the dialog {@link #dismiss()} or
+ * {@link #dismissAllowingStateLoss()}.
+ * <p>
+ * To create and show the progress dialog, use
+ * {@link #show(FragmentManager, CharSequence, CharSequence, long)} and retain the reference to the
+ * IndeterminateProgressDialog instance.
+ * <p>
+ * To dismiss the dialog, use {@link #dismiss()} or {@link #dismissAllowingStateLoss()} on the
+ * instance. The instance returned by
+ * {@link #show(FragmentManager, CharSequence, CharSequence, long)} is guaranteed to be valid
+ * after a device orientation change because the {@link #setRetainInstance(boolean)} is called
+ * internally with true.
+ */
+public class IndeterminateProgressDialog extends DialogFragment {
+ private static final String TAG = IndeterminateProgressDialog.class.getSimpleName();
+
+ private CharSequence mTitle;
+ private CharSequence mMessage;
+ private long mMinDisplayTime;
+ private long mShowTime = 0;
+ private boolean mActivityReady = false;
+ private Dialog mOldDialog;
+ private final Handler mHandler = new Handler();
+ private boolean mCalledSuperDismiss = false;
+ private boolean mAllowStateLoss;
+ private final Runnable mDismisser = new Runnable() {
+ @Override
+ public void run() {
+ superDismiss();
+ }
+ };
+
+ /**
+ * Creates and shows an indeterminate progress dialog. Once the progress dialog is shown, it
+ * will be shown for at least the minDisplayTime (in milliseconds), so that the progress dialog
+ * does not flash in and out to quickly.
+ */
+ public static IndeterminateProgressDialog show(FragmentManager fragmentManager,
+ CharSequence title, CharSequence message, long minDisplayTime) {
+ IndeterminateProgressDialog dialogFragment = new IndeterminateProgressDialog();
+ dialogFragment.mTitle = title;
+ dialogFragment.mMessage = message;
+ dialogFragment.mMinDisplayTime = minDisplayTime;
+ dialogFragment.show(fragmentManager, TAG);
+ dialogFragment.mShowTime = System.currentTimeMillis();
+ dialogFragment.setCancelable(false);
+
+ return dialogFragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRetainInstance(true);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Create the progress dialog and set its properties
+ final ProgressDialog dialog = new ProgressDialog(getActivity());
+ dialog.setIndeterminate(true);
+ dialog.setIndeterminateDrawable(null);
+ dialog.setTitle(mTitle);
+ dialog.setMessage(mMessage);
+
+ return dialog;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mActivityReady = true;
+
+ // Check if superDismiss() had been called before. This can happen if in a long
+ // running operation, the user hits the home button and closes this fragment's activity.
+ // Upon returning, we want to dismiss this progress dialog fragment.
+ if (mCalledSuperDismiss) {
+ superDismiss();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mActivityReady = false;
+ }
+
+ /**
+ * There is a race condition that is not handled properly by the DialogFragment class.
+ * If we don't check that this onDismiss callback isn't for the old progress dialog from before
+ * the device orientation change, then this will cause the newly created dialog after the
+ * orientation change to be dismissed immediately.
+ */
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ if (mOldDialog != null && mOldDialog == dialog) {
+ // This is the callback from the old progress dialog that was already dismissed before
+ // the device orientation change, so just ignore it.
+ return;
+ }
+ super.onDismiss(dialog);
+ }
+
+ /**
+ * Save the old dialog that is about to get destroyed in case this is due to a change
+ * in device orientation. This will allow us to intercept the callback to
+ * {@link #onDismiss(DialogInterface)} in case the callback happens after a new progress dialog
+ * instance was created.
+ */
+ @Override
+ public void onDestroyView() {
+ mOldDialog = getDialog();
+ super.onDestroyView();
+ }
+
+ /**
+ * This tells the progress dialog to dismiss itself after guaranteeing to be shown for the
+ * specified time in {@link #show(FragmentManager, CharSequence, CharSequence, long)}.
+ */
+ @Override
+ public void dismiss() {
+ mAllowStateLoss = false;
+ dismissWhenReady();
+ }
+
+ /**
+ * This tells the progress dialog to dismiss itself (with state loss) after guaranteeing to be
+ * shown for the specified time in
+ * {@link #show(FragmentManager, CharSequence, CharSequence, long)}.
+ */
+ @Override
+ public void dismissAllowingStateLoss() {
+ mAllowStateLoss = true;
+ dismissWhenReady();
+ }
+
+ /**
+ * Tells the progress dialog to dismiss itself after guaranteeing that the dialog had been
+ * showing for at least the minimum display time as set in
+ * {@link #show(FragmentManager, CharSequence, CharSequence, long)}.
+ */
+ private void dismissWhenReady() {
+ // Compute how long the dialog has been showing
+ final long shownTime = System.currentTimeMillis() - mShowTime;
+ if (shownTime >= mMinDisplayTime) {
+ // dismiss immediately
+ mHandler.post(mDismisser);
+ } else {
+ // Need to wait some more, so compute the amount of time to sleep.
+ final long sleepTime = mMinDisplayTime - shownTime;
+ mHandler.postDelayed(mDismisser, sleepTime);
+ }
+ }
+
+ /**
+ * Actually dismiss the dialog fragment.
+ */
+ private void superDismiss() {
+ mCalledSuperDismiss = true;
+ if (mActivityReady) {
+ // The fragment is either in onStart or past it, but has not gotten to onStop yet.
+ // It is safe to dismiss this dialog fragment.
+ if (mAllowStateLoss) {
+ super.dismissAllowingStateLoss();
+ } else {
+ super.dismiss();
+ }
+ }
+ // If mActivityReady is false, then this dialog fragment has already passed the onStop
+ // state. This can happen if the user hit the 'home' button before this dialog fragment was
+ // dismissed or if there is a configuration change.
+ // In the event that this dialog fragment is re-attached and reaches onStart (e.g.,
+ // because the user returns to this fragment's activity or the device configuration change
+ // has re-attached this dialog fragment), because the mCalledSuperDismiss flag was set to
+ // true, this dialog fragment will be dismissed within onStart. So, there's nothing else
+ // that needs to be done.
+ }
+}
diff --git a/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java b/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java
new file mode 100644
index 0000000..96da89a
--- /dev/null
+++ b/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010 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.common.editor;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.util.AccountsListAdapter;
+import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
+
+/**
+ * Shows a dialog asking the user which account to chose.
+ *
+ * The result is passed to {@code targetFragment} passed to {@link #show}.
+ */
+public final class SelectAccountDialogFragment extends DialogFragment {
+ public static final String TAG = "SelectAccountDialogFragment";
+
+ private static final String KEY_TITLE_RES_ID = "title_res_id";
+ private static final String KEY_LIST_FILTER = "list_filter";
+ private static final String KEY_EXTRA_ARGS = "extra_args";
+
+ public SelectAccountDialogFragment() { // All fragments must have a public default constructor.
+ }
+
+ /**
+ * Show the dialog.
+ *
+ * @param fragmentManager {@link FragmentManager}.
+ * @param targetFragment {@link Fragment} that implements {@link Listener}.
+ * @param titleResourceId resource ID to use as the title.
+ * @param accountListFilter account filter.
+ * @param extraArgs Extra arguments, which will later be passed to
+ * {@link Listener#onAccountChosen}. {@code null} will be converted to
+ * {@link Bundle#EMPTY}.
+ */
+ public static <F extends Fragment & Listener> void show(FragmentManager fragmentManager,
+ F targetFragment, int titleResourceId,
+ AccountListFilter accountListFilter, Bundle extraArgs) {
+ show(fragmentManager, targetFragment, titleResourceId, accountListFilter, extraArgs,
+ /* tag */ null);
+ }
+
+ public static <F extends Fragment & Listener> void show(FragmentManager fragmentManager,
+ F targetFragment, int titleResourceId,
+ AccountListFilter accountListFilter, Bundle extraArgs, String tag) {
+ final Bundle args = new Bundle();
+ args.putInt(KEY_TITLE_RES_ID, titleResourceId);
+ args.putSerializable(KEY_LIST_FILTER, accountListFilter);
+ args.putBundle(KEY_EXTRA_ARGS, (extraArgs == null) ? Bundle.EMPTY : extraArgs);
+
+ final SelectAccountDialogFragment instance = new SelectAccountDialogFragment();
+ instance.setArguments(args);
+ if (targetFragment != null) {
+ instance.setTargetFragment(targetFragment, 0);
+ }
+ instance.show(fragmentManager, tag);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ final Bundle args = getArguments();
+
+ final AccountListFilter filter = (AccountListFilter) args.getSerializable(KEY_LIST_FILTER);
+ final AccountsListAdapter accountAdapter = new AccountsListAdapter(builder.getContext(),
+ filter);
+ accountAdapter.setCustomLayout(R.layout.account_selector_list_item_condensed);
+
+ final DialogInterface.OnClickListener clickListener =
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+
+ onAccountSelected(accountAdapter.getItem(which));
+ }
+ };
+
+ final TextView title = (TextView) View.inflate(getActivity(), R.layout.dialog_title, null);
+ title.setText(args.getInt(KEY_TITLE_RES_ID));
+ builder.setCustomTitle(title);
+ builder.setSingleChoiceItems(accountAdapter, 0, clickListener);
+ final AlertDialog result = builder.create();
+ return result;
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ final Listener listener = getListener();
+ if (listener != null) {
+ listener.onAccountSelectorCancelled();
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle b) {
+ setTargetFragment(null, -1);
+ super.onSaveInstanceState(b);
+ }
+
+ /**
+ * Calls {@link Listener#onAccountChosen} of {@code targetFragment}.
+ */
+ private void onAccountSelected(AccountWithDataSet account) {
+ final Listener listener = getListener();
+ if (listener != null) {
+ listener.onAccountChosen(account, getArguments().getBundle(KEY_EXTRA_ARGS));
+ }
+ }
+
+ private Listener getListener() {
+ Listener listener = null;
+ final Fragment targetFragment = getTargetFragment();
+ if (targetFragment == null) {
+ final Activity activity = getActivity();
+ if (activity != null && activity instanceof Listener) {
+ listener = (Listener) activity;
+ }
+ } else if (targetFragment instanceof Listener) {
+ listener = (Listener) targetFragment;
+ }
+ return listener;
+ }
+
+ public interface Listener {
+ void onAccountChosen(AccountWithDataSet account, Bundle extraArgs);
+ void onAccountSelectorCancelled();
+ }
+}
diff --git a/src/com/android/contacts/common/extensions/ExtendedPhoneDirectoriesManager.java b/src/com/android/contacts/common/extensions/ExtendedPhoneDirectoriesManager.java
new file mode 100644
index 0000000..eb25934
--- /dev/null
+++ b/src/com/android/contacts/common/extensions/ExtendedPhoneDirectoriesManager.java
@@ -0,0 +1,26 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+
+package com.android.contacts.common.extensions;
+
+import android.content.Context;
+
+import com.android.contacts.common.list.DirectoryPartition;
+
+import java.util.List;
+
+/**
+ * An interface for adding extended phone directories to
+ * {@link com.android.contacts.common.list.PhoneNumberListAdapter}.
+ * An app that wishes to add custom phone directories should implement this class and advertise it
+ * in assets/contacts_extensions.properties. {@link ExtensionsFactory} will load the implementation
+ * and the extended directories will be added by
+ * {@link com.android.contacts.common.list.PhoneNumberListAdapter}.
+ */
+public interface ExtendedPhoneDirectoriesManager {
+
+ /**
+ * Return a list of extended directories to add. May return null if no directories are to be
+ * added.
+ */
+ List<DirectoryPartition> getExtendedDirectories(Context context);
+}
diff --git a/src/com/android/contacts/common/extensions/ExtensionsFactory.java b/src/com/android/contacts/common/extensions/ExtensionsFactory.java
new file mode 100644
index 0000000..d52429e
--- /dev/null
+++ b/src/com/android/contacts/common/extensions/ExtensionsFactory.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 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.common.extensions;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+
+/*
+ * A framework for adding extensions to Dialer. This class reads a property file from
+ * assets/contacts_extensions.properties and loads extension classes that an app has defined. If
+ * an extension class was not defined, null is returned.
+ */
+public class ExtensionsFactory {
+
+ private static String TAG = "ExtensionsFactory";
+
+ // Config filename for mappings of various class names to their custom
+ // implementations.
+ private static final String EXTENSIONS_PROPERTIES = "contacts_extensions.properties";
+
+ private static final String EXTENDED_PHONE_DIRECTORIES_KEY = "extendedPhoneDirectories";
+
+ private static Properties sProperties = null;
+ private static ExtendedPhoneDirectoriesManager mExtendedPhoneDirectoriesManager = null;
+
+ public static void init(Context context) {
+ if (sProperties != null) {
+ return;
+ }
+ try {
+ final InputStream fileStream = context.getAssets().open(EXTENSIONS_PROPERTIES);
+ sProperties = new Properties();
+ sProperties.load(fileStream);
+ fileStream.close();
+
+ final String className = sProperties.getProperty(EXTENDED_PHONE_DIRECTORIES_KEY);
+ if (className != null) {
+ mExtendedPhoneDirectoriesManager = createInstance(className);
+ } else {
+ Log.d(TAG, EXTENDED_PHONE_DIRECTORIES_KEY + " not found in properties file.");
+ }
+
+ } catch (FileNotFoundException e) {
+ // No custom extensions. Ignore.
+ Log.d(TAG, "No custom extensions.");
+ } catch (IOException e) {
+ Log.d(TAG, e.toString());
+ }
+ }
+
+ private static <T> T createInstance(String className) {
+ try {
+ Class<?> c = Class.forName(className);
+ //noinspection unchecked
+ return (T) c.newInstance();
+ } catch (ClassNotFoundException e) {
+ Log.e(TAG, className + ": unable to create instance.", e);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, className + ": unable to create instance.", e);
+ } catch (InstantiationException e) {
+ Log.e(TAG, className + ": unable to create instance.", e);
+ }
+ return null;
+ }
+
+ public static ExtendedPhoneDirectoriesManager getExtendedPhoneDirectoriesManager() {
+ return mExtendedPhoneDirectoriesManager;
+ }
+}
diff --git a/src/com/android/contacts/common/format/FormatUtils.java b/src/com/android/contacts/common/format/FormatUtils.java
new file mode 100644
index 0000000..376ff13
--- /dev/null
+++ b/src/com/android/contacts/common/format/FormatUtils.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2011 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.common.format;
+
+import android.database.CharArrayBuffer;
+import android.graphics.Typeface;
+import android.text.SpannableString;
+import android.text.style.StyleSpan;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+
+/**
+ * Assorted utility methods related to text formatting in Contacts.
+ */
+public class FormatUtils {
+
+ /**
+ * Finds the earliest point in buffer1 at which the first part of buffer2 matches. For example,
+ * overlapPoint("abcd", "cdef") == 2.
+ */
+ public static int overlapPoint(CharArrayBuffer buffer1, CharArrayBuffer buffer2) {
+ if (buffer1 == null || buffer2 == null) {
+ return -1;
+ }
+ return overlapPoint(Arrays.copyOfRange(buffer1.data, 0, buffer1.sizeCopied),
+ Arrays.copyOfRange(buffer2.data, 0, buffer2.sizeCopied));
+ }
+
+ /**
+ * Finds the earliest point in string1 at which the first part of string2 matches. For example,
+ * overlapPoint("abcd", "cdef") == 2.
+ */
+ @VisibleForTesting
+ public static int overlapPoint(String string1, String string2) {
+ if (string1 == null || string2 == null) {
+ return -1;
+ }
+ return overlapPoint(string1.toCharArray(), string2.toCharArray());
+ }
+
+ /**
+ * Finds the earliest point in array1 at which the first part of array2 matches. For example,
+ * overlapPoint("abcd", "cdef") == 2.
+ */
+ public static int overlapPoint(char[] array1, char[] array2) {
+ if (array1 == null || array2 == null) {
+ return -1;
+ }
+ int count1 = array1.length;
+ int count2 = array2.length;
+
+ // Ignore matching tails of the two arrays.
+ while (count1 > 0 && count2 > 0 && array1[count1 - 1] == array2[count2 - 1]) {
+ count1--;
+ count2--;
+ }
+
+ int size = count2;
+ for (int i = 0; i < count1; i++) {
+ if (i + size > count1) {
+ size = count1 - i;
+ }
+ int j;
+ for (j = 0; j < size; j++) {
+ if (array1[i+j] != array2[j]) {
+ break;
+ }
+ }
+ if (j == size) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Applies the given style to a range of the input CharSequence.
+ * @param style The style to apply (see the style constants in {@link Typeface}).
+ * @param input The CharSequence to style.
+ * @param start Starting index of the range to style (will be clamped to be a minimum of 0).
+ * @param end Ending index of the range to style (will be clamped to a maximum of the input
+ * length).
+ * @param flags Bitmask for configuring behavior of the span. See {@link android.text.Spanned}.
+ * @return The styled CharSequence.
+ */
+ public static CharSequence applyStyleToSpan(int style, CharSequence input, int start, int end,
+ int flags) {
+ // Enforce bounds of the char sequence.
+ start = Math.max(0, start);
+ end = Math.min(input.length(), end);
+ SpannableString text = new SpannableString(input);
+ text.setSpan(new StyleSpan(style), start, end, flags);
+ return text;
+ }
+
+ @VisibleForTesting
+ public static void copyToCharArrayBuffer(String text, CharArrayBuffer buffer) {
+ if (text != null) {
+ char[] data = buffer.data;
+ if (data == null || data.length < text.length()) {
+ buffer.data = text.toCharArray();
+ } else {
+ text.getChars(0, text.length(), data, 0);
+ }
+ buffer.sizeCopied = text.length();
+ } else {
+ buffer.sizeCopied = 0;
+ }
+ }
+
+ /** Returns a String that represents the content of the given {@link CharArrayBuffer}. */
+ @VisibleForTesting
+ public static String charArrayBufferToString(CharArrayBuffer buffer) {
+ return new String(buffer.data, 0, buffer.sizeCopied);
+ }
+
+ /**
+ * Finds the index of the first word that starts with the given prefix.
+ * <p>
+ * If not found, returns -1.
+ *
+ * @param text the text in which to search for the prefix
+ * @param prefix the text to find, in upper case letters
+ */
+ public static int indexOfWordPrefix(CharSequence text, String prefix) {
+ if (prefix == null || text == null) {
+ return -1;
+ }
+
+ int textLength = text.length();
+ int prefixLength = prefix.length();
+
+ if (prefixLength == 0 || textLength < prefixLength) {
+ return -1;
+ }
+
+ int i = 0;
+ while (i < textLength) {
+ // Skip non-word characters
+ while (i < textLength && !Character.isLetterOrDigit(text.charAt(i))) {
+ i++;
+ }
+
+ if (i + prefixLength > textLength) {
+ return -1;
+ }
+
+ // Compare the prefixes
+ int j;
+ for (j = 0; j < prefixLength; j++) {
+ if (Character.toUpperCase(text.charAt(i + j)) != prefix.charAt(j)) {
+ break;
+ }
+ }
+ if (j == prefixLength) {
+ return i;
+ }
+
+ // Skip this word
+ while (i < textLength && Character.isLetterOrDigit(text.charAt(i))) {
+ i++;
+ }
+ }
+
+ return -1;
+ }
+
+}
diff --git a/src/com/android/contacts/common/format/SpannedTestUtils.java b/src/com/android/contacts/common/format/SpannedTestUtils.java
new file mode 100644
index 0000000..463d7a8
--- /dev/null
+++ b/src/com/android/contacts/common/format/SpannedTestUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011 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.common.format;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Html;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.style.StyleSpan;
+import android.widget.TextView;
+
+import junit.framework.Assert;
+
+/**
+ * Utility class to check the value of spanned text in text views.
+ */
+@SmallTest
+public class SpannedTestUtils {
+ /**
+ * Checks that the text contained in the text view matches the given HTML text.
+ *
+ * @param expectedHtmlText the expected text to be in the text view
+ * @param textView the text view from which to get the text
+ */
+ public static void checkHtmlText(String expectedHtmlText, TextView textView) {
+ String actualHtmlText = Html.toHtml((Spanned) textView.getText());
+ if (TextUtils.isEmpty(expectedHtmlText)) {
+ // If the text is empty, it does not add the <p></p> bits to it.
+ Assert.assertEquals("", actualHtmlText);
+ } else {
+ Assert.assertEquals("<p dir=ltr>" + expectedHtmlText + "</p>\n", actualHtmlText);
+ }
+ }
+
+
+ /**
+ * Assert span exists in the correct location.
+ *
+ * @param seq The spannable string to check.
+ * @param start The starting index.
+ * @param end The ending index.
+ */
+ public static void assertPrefixSpan(CharSequence seq, int start, int end) {
+ Assert.assertTrue(seq instanceof Spanned);
+ Spanned spannable = (Spanned) seq;
+
+ if (start > 0) {
+ Assert.assertEquals(0, getNumForegroundColorSpansBetween(spannable, 0, start - 1));
+ }
+ Assert.assertEquals(1, getNumForegroundColorSpansBetween(spannable, start, end));
+ Assert.assertEquals(0, getNumForegroundColorSpansBetween(spannable, end + 1,
+ spannable.length() - 1));
+ }
+
+ private static int getNumForegroundColorSpansBetween(Spanned value, int start, int end) {
+ return value.getSpans(start, end, StyleSpan.class).length;
+ }
+
+ /**
+ * Asserts that the given character sequence is not a Spanned object and text is correct.
+ *
+ * @param seq The sequence to check.
+ * @param expected The expected text.
+ */
+ public static void assertNotSpanned(CharSequence seq, String expected) {
+ Assert.assertFalse(seq instanceof Spanned);
+ Assert.assertEquals(expected, seq);
+ }
+
+ public static int getNextTransition(SpannableString seq, int start) {
+ return seq.nextSpanTransition(start, seq.length(), StyleSpan.class);
+ }
+}
diff --git a/src/com/android/contacts/common/format/TextHighlighter.java b/src/com/android/contacts/common/format/TextHighlighter.java
new file mode 100644
index 0000000..496dcda
--- /dev/null
+++ b/src/com/android/contacts/common/format/TextHighlighter.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 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.common.format;
+
+import android.graphics.Typeface;
+import android.text.SpannableString;
+import android.text.style.CharacterStyle;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.StyleSpan;
+import android.widget.TextView;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Highlights the text in a text field.
+ */
+public class TextHighlighter {
+ private final String TAG = TextHighlighter.class.getSimpleName();
+ private final static boolean DEBUG = false;
+
+ private int mTextStyle;
+
+ private CharacterStyle mTextStyleSpan;
+
+ public TextHighlighter(int textStyle) {
+ mTextStyle = textStyle;
+ mTextStyleSpan = getStyleSpan();
+ }
+
+ /**
+ * Sets the text on the given text view, highlighting the word that matches the given prefix.
+ *
+ * @param view the view on which to set the text
+ * @param text the string to use as the text
+ * @param prefix the prefix to look for
+ */
+ public void setPrefixText(TextView view, String text, String prefix) {
+ view.setText(applyPrefixHighlight(text, prefix));
+ }
+
+ private CharacterStyle getStyleSpan() {
+ return new StyleSpan(mTextStyle);
+ }
+
+ /**
+ * Applies highlight span to the text.
+ * @param text Text sequence to be highlighted.
+ * @param start Start position of the highlight sequence.
+ * @param end End position of the highlight sequence.
+ */
+ public void applyMaskingHighlight(SpannableString text, int start, int end) {
+ /** Sets text color of the masked locations to be highlighted. */
+ text.setSpan(getStyleSpan(), start, end, 0);
+ }
+
+ /**
+ * Returns a CharSequence which highlights the given prefix if found in the given text.
+ *
+ * @param text the text to which to apply the highlight
+ * @param prefix the prefix to look for
+ */
+ public CharSequence applyPrefixHighlight(CharSequence text, String prefix) {
+ if (prefix == null) {
+ return text;
+ }
+
+ // Skip non-word characters at the beginning of prefix.
+ int prefixStart = 0;
+ while (prefixStart < prefix.length() &&
+ !Character.isLetterOrDigit(prefix.charAt(prefixStart))) {
+ prefixStart++;
+ }
+ final String trimmedPrefix = prefix.substring(prefixStart);
+
+ int index = FormatUtils.indexOfWordPrefix(text, trimmedPrefix);
+ if (index != -1) {
+ final SpannableString result = new SpannableString(text);
+ result.setSpan(mTextStyleSpan, index, index + trimmedPrefix.length(), 0 /* flags */);
+ return result;
+ } else {
+ return text;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
new file mode 100644
index 0000000..7e1b487
--- /dev/null
+++ b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2010 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.common.interactions;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract.Contacts;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
+import com.android.contacts.common.editor.SelectAccountDialogFragment;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.util.AccountSelectionUtil;
+import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
+import com.android.contacts.common.util.ImplicitIntentsUtil;
+import com.android.contacts.common.vcard.ExportVCardActivity;
+import com.android.contacts.common.vcard.VCardCommonArguments;
+import com.android.contacts.common.vcard.ShareVCardActivity;
+import com.android.contactsbind.analytics.AnalyticsUtil;
+
+import java.util.List;
+
+/**
+ * An dialog invoked to import/export contacts.
+ */
+public class ImportExportDialogFragment extends DialogFragment
+ implements SelectAccountDialogFragment.Listener {
+ public static final String TAG = "ImportExportDialogFragment";
+
+ public static final int EXPORT_MODE_FAVORITES = 0;
+ public static final int EXPORT_MODE_ALL_CONTACTS = 1;
+ public static final int EXPORT_MODE_DEFAULT = -1;
+
+ private static final String KEY_RES_ID = "resourceId";
+ private static final String KEY_SUBSCRIPTION_ID = "subscriptionId";
+ private static final String ARG_CONTACTS_ARE_AVAILABLE = "CONTACTS_ARE_AVAILABLE";
+
+ private static int mExportMode = EXPORT_MODE_DEFAULT;
+
+ private final String[] LOOKUP_PROJECTION = new String[] {
+ Contacts.LOOKUP_KEY
+ };
+
+ private SubscriptionManager mSubscriptionManager;
+
+ /** Preferred way to show this dialog */
+ public static void show(FragmentManager fragmentManager, boolean contactsAreAvailable,
+ Class callingActivity, int exportMode) {
+ final ImportExportDialogFragment fragment = new ImportExportDialogFragment();
+ Bundle args = new Bundle();
+ args.putBoolean(ARG_CONTACTS_ARE_AVAILABLE, contactsAreAvailable);
+ args.putString(VCardCommonArguments.ARG_CALLING_ACTIVITY, callingActivity.getName());
+ fragment.setArguments(args);
+ fragment.show(fragmentManager, ImportExportDialogFragment.TAG);
+ mExportMode = exportMode;
+ }
+
+ @Override
+ public Context getContext() {
+ return getActivity();
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Wrap our context to inflate list items using the correct theme
+ final Resources res = getActivity().getResources();
+ final LayoutInflater dialogInflater = (LayoutInflater)getActivity()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ final boolean contactsAreAvailable = getArguments().getBoolean(ARG_CONTACTS_ARE_AVAILABLE);
+ final String callingActivity = getArguments().getString(
+ VCardCommonArguments.ARG_CALLING_ACTIVITY);
+
+ // Adapter that shows a list of string resources
+ final ArrayAdapter<AdapterEntry> adapter = new ArrayAdapter<AdapterEntry>(getActivity(),
+ R.layout.select_dialog_item) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final TextView result = (TextView)(convertView != null ? convertView :
+ dialogInflater.inflate(R.layout.select_dialog_item, parent, false));
+
+ result.setText(getItem(position).mLabel);
+ return result;
+ }
+ };
+
+ final TelephonyManager manager =
+ (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
+ if (res.getBoolean(R.bool.config_allow_import_from_vcf_file)) {
+ adapter.add(new AdapterEntry(getString(R.string.import_from_vcf_file),
+ R.string.import_from_vcf_file));
+ }
+
+ if (CompatUtils.isMSIMCompatible()) {
+ mSubscriptionManager = SubscriptionManager.from(getActivity());
+ if (manager != null && res.getBoolean(R.bool.config_allow_sim_import)) {
+ List<SubscriptionInfo> subInfoRecords = null;
+ try {
+ subInfoRecords = mSubscriptionManager.getActiveSubscriptionInfoList();
+ } catch (SecurityException e) {
+ Log.w(TAG, "SecurityException thrown, lack permission for"
+ + " getActiveSubscriptionInfoList", e);
+ }
+ if (subInfoRecords != null) {
+ if (subInfoRecords.size() == 1) {
+ adapter.add(new AdapterEntry(getString(R.string.import_from_sim),
+ R.string.import_from_sim, subInfoRecords.get(0).getSubscriptionId()));
+ } else {
+ for (SubscriptionInfo record : subInfoRecords) {
+ adapter.add(new AdapterEntry(getSubDescription(record),
+ R.string.import_from_sim, record.getSubscriptionId()));
+ }
+ }
+ }
+ }
+ } else {
+ if (manager != null && manager.hasIccCard()
+ && res.getBoolean(R.bool.config_allow_sim_import)) {
+ adapter.add(new AdapterEntry(getString(R.string.import_from_sim),
+ R.string.import_from_sim, -1));
+ }
+ }
+
+ if (res.getBoolean(R.bool.config_allow_export)) {
+ if (contactsAreAvailable) {
+ adapter.add(new AdapterEntry(getString(R.string.export_to_vcf_file),
+ R.string.export_to_vcf_file));
+ }
+ }
+ if (res.getBoolean(R.bool.config_allow_share_contacts) && contactsAreAvailable) {
+ if (mExportMode == EXPORT_MODE_FAVORITES) {
+ // share favorite and frequently contacted contacts from Favorites tab
+ adapter.add(new AdapterEntry(getString(R.string.share_favorite_contacts),
+ R.string.share_contacts));
+ } else {
+ // share "all" contacts (in groups selected in "Customize") from All tab for now
+ // TODO: change the string to share_visible_contacts if implemented
+ adapter.add(new AdapterEntry(getString(R.string.share_contacts),
+ R.string.share_contacts));
+ }
+ }
+
+ final DialogInterface.OnClickListener clickListener =
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ boolean dismissDialog;
+ final int resId = adapter.getItem(which).mChoiceResourceId;
+ if (resId == R.string.import_from_sim || resId == R.string.import_from_vcf_file) {
+ dismissDialog = handleImportRequest(resId,
+ adapter.getItem(which).mSubscriptionId);
+ } else if (resId == R.string.export_to_vcf_file) {
+ dismissDialog = true;
+ final Intent exportIntent = new Intent(
+ getActivity(), ExportVCardActivity.class);
+ exportIntent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY,
+ callingActivity);
+ getActivity().startActivity(exportIntent);
+ } else if (resId == R.string.share_contacts) {
+ dismissDialog = true;
+ if (mExportMode == EXPORT_MODE_FAVORITES) {
+ doShareFavoriteContacts();
+ } else { // EXPORT_MODE_ALL_CONTACTS
+ final Intent exportIntent = new Intent(
+ getActivity(), ShareVCardActivity.class);
+ exportIntent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY,
+ callingActivity);
+ getActivity().startActivity(exportIntent);
+ }
+ } else {
+ dismissDialog = true;
+ Log.e(TAG, "Unexpected resource: "
+ + getActivity().getResources().getResourceEntryName(resId));
+ }
+ if (dismissDialog) {
+ dialog.dismiss();
+ }
+ }
+ };
+ final TextView title = (TextView) View.inflate(getActivity(), R.layout.dialog_title, null);
+ title.setText(contactsAreAvailable
+ ? R.string.dialog_import_export
+ : R.string.dialog_import);
+ return new AlertDialog.Builder(getActivity())
+ .setCustomTitle(title)
+ .setSingleChoiceItems(adapter, -1, clickListener)
+ .create();
+ }
+
+ private void doShareFavoriteContacts() {
+ try{
+ final Cursor cursor = getActivity().getContentResolver().query(
+ Contacts.CONTENT_STREQUENT_URI, LOOKUP_PROJECTION, null, null,
+ Contacts.DISPLAY_NAME + " COLLATE NOCASE ASC");
+ if (cursor != null) {
+ try {
+ if (!cursor.moveToFirst()) {
+ Toast.makeText(getActivity(), R.string.no_contact_to_share,
+ Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // Build multi-vcard Uri for sharing
+ final StringBuilder uriListBuilder = new StringBuilder();
+ int index = 0;
+ do {
+ if (index != 0)
+ uriListBuilder.append(':');
+ uriListBuilder.append(cursor.getString(0));
+ index++;
+ } while (cursor.moveToNext());
+ final Uri uri = Uri.withAppendedPath(
+ Contacts.CONTENT_MULTI_VCARD_URI,
+ Uri.encode(uriListBuilder.toString()));
+
+ final Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType(Contacts.CONTENT_VCARD_TYPE);
+ intent.putExtra(Intent.EXTRA_STREAM, uri);
+ ImplicitIntentsUtil.startActivityOutsideApp(getActivity(), intent);
+ } finally {
+ cursor.close();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Sharing contacts failed", e);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(getContext(), R.string.share_contacts_failure,
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ }
+
+ /**
+ * Handle "import from SIM" and "import from SD".
+ *
+ * @return {@code true} if the dialog show be closed. {@code false} otherwise.
+ */
+ private boolean handleImportRequest(int resId, int subscriptionId) {
+ // There are 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 AccountTypeManager accountTypes = AccountTypeManager.getInstance(getActivity());
+ final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
+ final int size = accountList.size();
+ if (size > 1) {
+ // Send over to the account selector
+ final Bundle args = new Bundle();
+ args.putInt(KEY_RES_ID, resId);
+ args.putInt(KEY_SUBSCRIPTION_ID, subscriptionId);
+ SelectAccountDialogFragment.show(
+ getFragmentManager(), this,
+ R.string.dialog_new_contact_account,
+ AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, args);
+
+ // In this case, because this DialogFragment is used as a target fragment to
+ // SelectAccountDialogFragment, we can't close it yet. We close the dialog when
+ // we get a callback from it.
+ return false;
+ }
+
+ AccountSelectionUtil.doImport(getActivity(), resId,
+ (size == 1 ? accountList.get(0) : null),
+ (CompatUtils.isMSIMCompatible() ? subscriptionId : -1));
+ return true; // Close the dialog.
+ }
+
+ /**
+ * Called when an account is selected on {@link SelectAccountDialogFragment}.
+ */
+ @Override
+ public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
+ AccountSelectionUtil.doImport(getActivity(), extraArgs.getInt(KEY_RES_ID),
+ account, extraArgs.getInt(KEY_SUBSCRIPTION_ID));
+
+ // At this point the dialog is still showing (which is why we can use getActivity() above)
+ // So close it.
+ dismiss();
+ }
+
+ @Override
+ public void onAccountSelectorCancelled() {
+ // See onAccountChosen() -- at this point the dialog is still showing. Close it.
+ dismiss();
+ }
+
+ private CharSequence getSubDescription(SubscriptionInfo record) {
+ CharSequence name = record.getDisplayName();
+ if (TextUtils.isEmpty(record.getNumber())) {
+ // Don't include the phone number in the description, since we don't know the number.
+ return getString(R.string.import_from_sim_summary_no_number, name);
+ }
+ return TextUtils.expandTemplate(
+ getString(R.string.import_from_sim_summary),
+ name,
+ PhoneNumberUtilsCompat.createTtsSpannable(record.getNumber()));
+ }
+
+ private static class AdapterEntry {
+ public final CharSequence mLabel;
+ public final int mChoiceResourceId;
+ public final int mSubscriptionId;
+
+ public AdapterEntry(CharSequence label, int resId, int subId) {
+ mLabel = label;
+ mChoiceResourceId = resId;
+ mSubscriptionId = subId;
+ }
+
+ public AdapterEntry(String label, int resId) {
+ // Store a nonsense value for mSubscriptionId. If this constructor is used,
+ // the mSubscriptionId value should not be read later.
+ this(label, resId, /* subId = */ -1);
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/interactions/TouchPointManager.java b/src/com/android/contacts/common/interactions/TouchPointManager.java
new file mode 100644
index 0000000..4c38e22
--- /dev/null
+++ b/src/com/android/contacts/common/interactions/TouchPointManager.java
@@ -0,0 +1,46 @@
+package com.android.contacts.common.interactions;
+
+import android.graphics.Point;
+
+/**
+ * Singleton class to keep track of where the user last touched the screen.
+ *
+ * Used to pass on to the InCallUI for animation.
+ */
+public class TouchPointManager {
+ public static final String TOUCH_POINT = "touchPoint";
+
+ private static TouchPointManager sInstance = new TouchPointManager();
+
+ private Point mPoint = new Point();
+
+ /**
+ * Private constructor. Instance should only be acquired through getInstance().
+ */
+ private TouchPointManager() {
+ }
+
+ public static TouchPointManager getInstance() {
+ return sInstance;
+ }
+
+ public Point getPoint() {
+ return mPoint;
+ }
+
+ public void setPoint(int x, int y) {
+ mPoint.set(x, y);
+ }
+
+ /**
+ * When a point is initialized, its value is (0,0). Since it is highly unlikely a user will
+ * touch at that exact point, if the point in TouchPointManager is (0,0), it is safe to assume
+ * that the TouchPointManager has not yet collected a touch.
+ *
+ * @return True if there is a valid point saved. Define a valid point as any point that is
+ * not (0,0).
+ */
+ public boolean hasValidPoint() {
+ return mPoint.x != 0 || mPoint.y != 0;
+ }
+}
diff --git a/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java b/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java
new file mode 100644
index 0000000..d1f1811
--- /dev/null
+++ b/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2013 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.common.lettertiles;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+
+import com.android.contacts.common.R;
+
+import junit.framework.Assert;
+
+/**
+ * A drawable that encapsulates all the functionality needed to display a letter tile to
+ * represent a contact image.
+ */
+public class LetterTileDrawable extends Drawable {
+
+ private final String TAG = LetterTileDrawable.class.getSimpleName();
+
+ private final Paint mPaint;
+
+ /** Letter tile */
+ private static TypedArray sColors;
+ private static int sDefaultColor;
+ private static int sTileFontColor;
+ private static float sLetterToTileRatio;
+ private static Bitmap DEFAULT_PERSON_AVATAR;
+ private static Bitmap DEFAULT_BUSINESS_AVATAR;
+ private static Bitmap DEFAULT_VOICEMAIL_AVATAR;
+
+ /** Reusable components to avoid new allocations */
+ private static final Paint sPaint = new Paint();
+ private static final Rect sRect = new Rect();
+ private static final char[] sFirstChar = new char[1];
+
+ /** Contact type constants */
+ public static final int TYPE_PERSON = 1;
+ public static final int TYPE_BUSINESS = 2;
+ public static final int TYPE_VOICEMAIL = 3;
+ public static final int TYPE_DEFAULT = TYPE_PERSON;
+
+ /** 54% opacity */
+ private static final int ALPHA = 138;
+
+ private int mContactType = TYPE_DEFAULT;
+ private float mScale = 1.0f;
+ private float mOffset = 0.0f;
+ private boolean mIsCircle = false;
+
+ private int mColor;
+ private Character mLetter = null;
+
+ public LetterTileDrawable(final Resources res) {
+ if (sColors == null) {
+ sColors = res.obtainTypedArray(R.array.letter_tile_colors);
+ sDefaultColor = res.getColor(R.color.letter_tile_default_color);
+ sTileFontColor = res.getColor(R.color.letter_tile_font_color);
+ sLetterToTileRatio = res.getFraction(R.dimen.letter_to_tile_ratio, 1, 1);
+ DEFAULT_PERSON_AVATAR = BitmapFactory.decodeResource(res,
+ R.drawable.ic_person_avatar);
+ DEFAULT_BUSINESS_AVATAR = BitmapFactory.decodeResource(res,
+ R.drawable.ic_business_white_120dp);
+ DEFAULT_VOICEMAIL_AVATAR = BitmapFactory.decodeResource(res,
+ R.drawable.ic_voicemail_avatar);
+ sPaint.setTypeface(Typeface.create(
+ res.getString(R.string.letter_tile_letter_font_family), Typeface.NORMAL));
+ sPaint.setTextAlign(Align.CENTER);
+ sPaint.setAntiAlias(true);
+ }
+ mPaint = new Paint();
+ mPaint.setFilterBitmap(true);
+ mPaint.setDither(true);
+ mColor = sDefaultColor;
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ final Rect bounds = getBounds();
+ if (!isVisible() || bounds.isEmpty()) {
+ return;
+ }
+ // Draw letter tile.
+ drawLetterTile(canvas);
+ }
+
+ /**
+ * Draw the bitmap onto the canvas at the current bounds taking into account the current scale.
+ */
+ private void drawBitmap(final Bitmap bitmap, final int width, final int height,
+ final Canvas canvas) {
+ // The bitmap should be drawn in the middle of the canvas without changing its width to
+ // height ratio.
+ final Rect destRect = copyBounds();
+
+ // Crop the destination bounds into a square, scaled and offset as appropriate
+ final int halfLength = (int) (mScale * Math.min(destRect.width(), destRect.height()) / 2);
+
+ destRect.set(destRect.centerX() - halfLength,
+ (int) (destRect.centerY() - halfLength + mOffset * destRect.height()),
+ destRect.centerX() + halfLength,
+ (int) (destRect.centerY() + halfLength + mOffset * destRect.height()));
+
+ // Source rectangle remains the entire bounds of the source bitmap.
+ sRect.set(0, 0, width, height);
+
+ sPaint.setTextAlign(Align.CENTER);
+ sPaint.setAntiAlias(true);
+ sPaint.setAlpha(ALPHA);
+
+ canvas.drawBitmap(bitmap, sRect, destRect, sPaint);
+ }
+
+ private void drawLetterTile(final Canvas canvas) {
+ // Draw background color.
+ sPaint.setColor(mColor);
+
+ sPaint.setAlpha(mPaint.getAlpha());
+ final Rect bounds = getBounds();
+ final int minDimension = Math.min(bounds.width(), bounds.height());
+
+ if (mIsCircle) {
+ canvas.drawCircle(bounds.centerX(), bounds.centerY(), minDimension / 2, sPaint);
+ } else {
+ canvas.drawRect(bounds, sPaint);
+ }
+
+ // Draw letter/digit only if the first character is an english letter or there's a override
+
+ if (mLetter != null) {
+ // Draw letter or digit.
+ sFirstChar[0] = mLetter;
+
+ // Scale text by canvas bounds and user selected scaling factor
+ sPaint.setTextSize(mScale * sLetterToTileRatio * minDimension);
+ sPaint.getTextBounds(sFirstChar, 0, 1, sRect);
+ sPaint.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL));
+ sPaint.setColor(sTileFontColor);
+ sPaint.setAlpha(ALPHA);
+
+ // Draw the letter in the canvas, vertically shifted up or down by the user-defined
+ // offset
+ canvas.drawText(sFirstChar, 0, 1, bounds.centerX(),
+ bounds.centerY() + mOffset * bounds.height() - sRect.exactCenterY(),
+ sPaint);
+ } else {
+ // Draw the default image if there is no letter/digit to be drawn
+ final Bitmap bitmap = getBitmapForContactType(mContactType);
+ drawBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(),
+ canvas);
+ }
+ }
+
+ public int getColor() {
+ return mColor;
+ }
+
+ /**
+ * Returns a deterministic color based on the provided contact identifier string.
+ */
+ private int pickColor(final String identifier) {
+ if (TextUtils.isEmpty(identifier) || mContactType == TYPE_VOICEMAIL) {
+ return sDefaultColor;
+ }
+ // String.hashCode() implementation is not supposed to change across java versions, so
+ // this should guarantee the same email address always maps to the same color.
+ // The email should already have been normalized by the ContactRequest.
+ final int color = Math.abs(identifier.hashCode()) % sColors.length();
+ return sColors.getColor(color, sDefaultColor);
+ }
+
+ private static Bitmap getBitmapForContactType(int contactType) {
+ switch (contactType) {
+ case TYPE_PERSON:
+ return DEFAULT_PERSON_AVATAR;
+ case TYPE_BUSINESS:
+ return DEFAULT_BUSINESS_AVATAR;
+ case TYPE_VOICEMAIL:
+ return DEFAULT_VOICEMAIL_AVATAR;
+ default:
+ return DEFAULT_PERSON_AVATAR;
+ }
+ }
+
+ private static boolean isEnglishLetter(final char c) {
+ return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
+ }
+
+ @Override
+ public void setAlpha(final int alpha) {
+ mPaint.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(final ColorFilter cf) {
+ mPaint.setColorFilter(cf);
+ }
+
+ @Override
+ public int getOpacity() {
+ return android.graphics.PixelFormat.OPAQUE;
+ }
+
+ /**
+ * Scale the drawn letter tile to a ratio of its default size
+ *
+ * @param scale The ratio the letter tile should be scaled to as a percentage of its default
+ * size, from a scale of 0 to 2.0f. The default is 1.0f.
+ */
+ public LetterTileDrawable setScale(float scale) {
+ mScale = scale;
+ return this;
+ }
+
+ /**
+ * Assigns the vertical offset of the position of the letter tile to the ContactDrawable
+ *
+ * @param offset The provided offset must be within the range of -0.5f to 0.5f.
+ * If set to -0.5f, the letter will be shifted upwards by 0.5 times the height of the canvas
+ * it is being drawn on, which means it will be drawn with the center of the letter starting
+ * at the top edge of the canvas.
+ * If set to 0.5f, the letter will be shifted downwards by 0.5 times the height of the canvas
+ * it is being drawn on, which means it will be drawn with the center of the letter starting
+ * at the bottom edge of the canvas.
+ * The default is 0.0f.
+ */
+ public LetterTileDrawable setOffset(float offset) {
+ Assert.assertTrue(offset >= -0.5f && offset <= 0.5f);
+ mOffset = offset;
+ return this;
+ }
+
+ public LetterTileDrawable setLetter(Character letter){
+ mLetter = letter;
+ return this;
+ }
+
+ public LetterTileDrawable setColor(int color){
+ mColor = color;
+ return this;
+ }
+
+ public LetterTileDrawable setLetterAndColorFromContactDetails(final String displayName,
+ final String identifier) {
+ if (displayName != null && displayName.length() > 0
+ && isEnglishLetter(displayName.charAt(0))) {
+ mLetter = Character.toUpperCase(displayName.charAt(0));
+ }else{
+ mLetter = null;
+ }
+ mColor = pickColor(identifier);
+ return this;
+ }
+
+ public LetterTileDrawable setContactType(int contactType) {
+ mContactType = contactType;
+ return this;
+ }
+
+ public LetterTileDrawable setIsCircular(boolean isCircle) {
+ mIsCircle = isCircle;
+ return this;
+ }
+}
diff --git a/src/com/android/contacts/common/list/AccountFilterActivity.java b/src/com/android/contacts/common/list/AccountFilterActivity.java
new file mode 100644
index 0000000..bed6977
--- /dev/null
+++ b/src/com/android/contacts/common/list/AccountFilterActivity.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2011 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.common.list;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.AccountTypeManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Shows a list of all available accounts, letting the user select under which account to view
+ * contacts.
+ */
+public class AccountFilterActivity extends Activity implements AdapterView.OnItemClickListener {
+
+ private static final int SUBACTIVITY_CUSTOMIZE_FILTER = 0;
+
+ public static final String EXTRA_CONTACT_LIST_FILTER = "contactListFilter";
+
+ private ListView mListView;
+
+ // The default contact list type, it should be either FILTER_TYPE_ALL_ACCOUNTS or
+ // FILTER_TYPE_CUSTOM, since those are the only two options we give the user.
+ private int mCurrentFilterType;
+
+ private ContactListFilterView mCustomFilterView; // the "Customize" filter
+
+ private boolean mIsCustomFilterViewSelected;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.contact_list_filter);
+
+ mListView = (ListView) findViewById(android.R.id.list);
+ mListView.setOnItemClickListener(this);
+
+ ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
+
+ mCurrentFilterType = ContactListFilterController.getInstance(this).isCustomFilterPersisted()
+ ? ContactListFilter.FILTER_TYPE_CUSTOM
+ : ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS;
+
+ // We don't need to use AccountFilterUtil.FilterLoader since we only want to show
+ // the "All contacts" and "Customize" options.
+ final List<ContactListFilter> filters = new ArrayList<>();
+ filters.add(ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS));
+ filters.add(ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_CUSTOM));
+ mListView.setAdapter(new FilterListAdapter(this, filters, mCurrentFilterType));
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ final ContactListFilterView listFilterView = (ContactListFilterView) view;
+ final ContactListFilter filter = (ContactListFilter) view.getTag();
+ if (filter == null) return; // Just in case
+ if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) {
+ mCustomFilterView = listFilterView;
+ mIsCustomFilterViewSelected = listFilterView.isChecked();
+ final Intent intent = new Intent(this,
+ CustomContactListFilterActivity.class);
+ listFilterView.setActivated(true);
+ // Switching activity has the highest priority. So when we open another activity, the
+ // announcement that indicates an account is checked will be interrupted. This is the
+ // way to overcome -- View.announceForAccessibility(CharSequence text);
+ listFilterView.announceForAccessibility(listFilterView.generateContentDescription());
+ startActivityForResult(intent, SUBACTIVITY_CUSTOMIZE_FILTER);
+ } else {
+ listFilterView.setActivated(true);
+ listFilterView.announceForAccessibility(listFilterView.generateContentDescription());
+ final Intent intent = new Intent();
+ intent.putExtra(EXTRA_CONTACT_LIST_FILTER, filter);
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == Activity.RESULT_CANCELED && mCustomFilterView != null &&
+ !mIsCustomFilterViewSelected) {
+ mCustomFilterView.setActivated(false);
+ return;
+ }
+
+ if (resultCode != Activity.RESULT_OK) {
+ return;
+ }
+
+ switch (requestCode) {
+ case SUBACTIVITY_CUSTOMIZE_FILTER: {
+ final Intent intent = new Intent();
+ ContactListFilter filter = ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_CUSTOM);
+ intent.putExtra(EXTRA_CONTACT_LIST_FILTER, filter);
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ break;
+ }
+ }
+ }
+
+ private static class FilterListAdapter extends BaseAdapter {
+ private final List<ContactListFilter> mFilters;
+ private final LayoutInflater mLayoutInflater;
+ private final AccountTypeManager mAccountTypes;
+ private final int mCurrentFilter;
+
+ public FilterListAdapter(
+ Context context, List<ContactListFilter> filters, int current) {
+ mLayoutInflater = (LayoutInflater) context.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ mFilters = filters;
+ mCurrentFilter = current;
+ mAccountTypes = AccountTypeManager.getInstance(context);
+ }
+
+ @Override
+ public int getCount() {
+ return mFilters.size();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public ContactListFilter getItem(int position) {
+ return mFilters.get(position);
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final ContactListFilterView view;
+ if (convertView != null) {
+ view = (ContactListFilterView) convertView;
+ } else {
+ view = (ContactListFilterView) mLayoutInflater.inflate(
+ R.layout.contact_list_filter_item, parent, false);
+ }
+ view.setSingleAccount(mFilters.size() == 1);
+ final ContactListFilter filter = mFilters.get(position);
+ view.setContactListFilter(filter);
+ view.bindView(mAccountTypes);
+ view.setTag(filter);
+ view.setActivated(filter.filterType == mCurrentFilter);
+ return view;
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ // We have two logical "up" Activities: People and Phone.
+ // Instead of having one static "up" direction, behave like back as an
+ // exceptional case.
+ onBackPressed();
+ return true;
+ default:
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/src/com/android/contacts/common/list/AutoScrollListView.java b/src/com/android/contacts/common/list/AutoScrollListView.java
new file mode 100644
index 0000000..ae7ca17
--- /dev/null
+++ b/src/com/android/contacts/common/list/AutoScrollListView.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ListView;
+
+/**
+ * A ListView that can be asked to scroll (smoothly or otherwise) to a specific
+ * position. This class takes advantage of similar functionality that exists
+ * in {@link ListView} and enhances it.
+ */
+public class AutoScrollListView extends ListView {
+
+ /**
+ * Position the element at about 1/3 of the list height
+ */
+ private static final float PREFERRED_SELECTION_OFFSET_FROM_TOP = 0.33f;
+
+ private int mRequestedScrollPosition = -1;
+ private boolean mSmoothScrollRequested;
+
+ public AutoScrollListView(Context context) {
+ super(context);
+ }
+
+ public AutoScrollListView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AutoScrollListView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Brings the specified position to view by optionally performing a jump-scroll maneuver:
+ * first it jumps to some position near the one requested and then does a smooth
+ * scroll to the requested position. This creates an impression of full smooth
+ * scrolling without actually traversing the entire list. If smooth scrolling is
+ * not requested, instantly positions the requested item at a preferred offset.
+ */
+ public void requestPositionToScreen(int position, boolean smoothScroll) {
+ mRequestedScrollPosition = position;
+ mSmoothScrollRequested = smoothScroll;
+ requestLayout();
+ }
+
+ @Override
+ protected void layoutChildren() {
+ super.layoutChildren();
+ if (mRequestedScrollPosition == -1) {
+ return;
+ }
+
+ final int position = mRequestedScrollPosition;
+ mRequestedScrollPosition = -1;
+
+ int firstPosition = getFirstVisiblePosition() + 1;
+ int lastPosition = getLastVisiblePosition();
+ if (position >= firstPosition && position <= lastPosition) {
+ return; // Already on screen
+ }
+
+ final int offset = (int) (getHeight() * PREFERRED_SELECTION_OFFSET_FROM_TOP);
+ if (!mSmoothScrollRequested) {
+ setSelectionFromTop(position, offset);
+
+ // Since we have changed the scrolling position, we need to redo child layout
+ // Calling "requestLayout" in the middle of a layout pass has no effect,
+ // so we call layoutChildren explicitly
+ super.layoutChildren();
+
+ } else {
+ // We will first position the list a couple of screens before or after
+ // the new selection and then scroll smoothly to it.
+ int twoScreens = (lastPosition - firstPosition) * 2;
+ int preliminaryPosition;
+ if (position < firstPosition) {
+ preliminaryPosition = position + twoScreens;
+ if (preliminaryPosition >= getCount()) {
+ preliminaryPosition = getCount() - 1;
+ }
+ if (preliminaryPosition < firstPosition) {
+ setSelection(preliminaryPosition);
+ super.layoutChildren();
+ }
+ } else {
+ preliminaryPosition = position - twoScreens;
+ if (preliminaryPosition < 0) {
+ preliminaryPosition = 0;
+ }
+ if (preliminaryPosition > lastPosition) {
+ setSelection(preliminaryPosition);
+ super.layoutChildren();
+ }
+ }
+
+
+ smoothScrollToPositionFromTop(position, offset);
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactEntry.java b/src/com/android/contacts/common/list/ContactEntry.java
new file mode 100644
index 0000000..a29a8d8
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactEntry.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 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.common.list;
+
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.ContactsContract.PinnedPositions;
+import android.text.TextUtils;
+
+import com.android.contacts.common.preference.ContactsPreferences;
+
+/**
+ * Class to hold contact information
+ */
+public class ContactEntry {
+
+ private static final int UNSET_DISPLAY_ORDER_PREFERENCE = -1;
+
+ /**
+ * Primary name for a Contact
+ */
+ public String namePrimary;
+ /**
+ * Alternative name for a Contact, e.g. last name first
+ */
+ public String nameAlternative;
+ /**
+ * The user's preference on name display order, last name first or first time first.
+ * {@see ContactsPreferences}
+ */
+ public int nameDisplayOrder = UNSET_DISPLAY_ORDER_PREFERENCE;
+
+ public String status;
+ public String phoneLabel;
+ public String phoneNumber;
+ public Uri photoUri;
+ public Uri lookupUri;
+ public String lookupKey;
+ public Drawable presenceIcon;
+ public long id;
+ public int pinned = PinnedPositions.UNPINNED;
+ public boolean isFavorite = false;
+ public boolean isDefaultNumber = false;
+
+ public static final ContactEntry BLANK_ENTRY = new ContactEntry();
+
+ public String getPreferredDisplayName() {
+ if (nameDisplayOrder == UNSET_DISPLAY_ORDER_PREFERENCE
+ || nameDisplayOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY
+ || TextUtils.isEmpty(nameAlternative)) {
+ return namePrimary;
+ }
+ return nameAlternative;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/common/list/ContactEntryListAdapter.java b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
new file mode 100644
index 0000000..1ac8fd5
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Directory;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.QuickContactBadge;
+import android.widget.SectionIndexer;
+import android.widget.TextView;
+
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.DirectoryCompat;
+import com.android.contacts.common.util.SearchUtil;
+
+import java.util.HashSet;
+
+/**
+ * Common base class for various contact-related lists, e.g. contact list, phone number list
+ * etc.
+ */
+public abstract class ContactEntryListAdapter extends IndexerListAdapter {
+
+ private static final String TAG = "ContactEntryListAdapter";
+
+ /**
+ * Indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should
+ * be included in the search.
+ */
+ public static final boolean LOCAL_INVISIBLE_DIRECTORY_ENABLED = false;
+
+ private int mDisplayOrder;
+ private int mSortOrder;
+
+ private boolean mDisplayPhotos;
+ private boolean mCircularPhotos = true;
+ private boolean mQuickContactEnabled;
+ private boolean mAdjustSelectionBoundsEnabled;
+
+ /**
+ * indicates if contact queries include favorites
+ */
+ private boolean mIncludeFavorites;
+
+ private int mNumberOfFavorites;
+
+ /**
+ * The root view of the fragment that this adapter is associated with.
+ */
+ private View mFragmentRootView;
+
+ private ContactPhotoManager mPhotoLoader;
+
+ private String mQueryString;
+ private String mUpperCaseQueryString;
+ private boolean mSearchMode;
+ private int mDirectorySearchMode;
+ private int mDirectoryResultLimit = Integer.MAX_VALUE;
+
+ private boolean mEmptyListEnabled = true;
+
+ private boolean mSelectionVisible;
+
+ private ContactListFilter mFilter;
+ private boolean mDarkTheme = false;
+
+ /** Resource used to provide header-text for default filter. */
+ private CharSequence mDefaultFilterHeaderText;
+
+ public ContactEntryListAdapter(Context context) {
+ super(context);
+ setDefaultFilterHeaderText(R.string.local_search_label);
+ addPartitions();
+ }
+
+ /**
+ * @param fragmentRootView Root view of the fragment. This is used to restrict the scope of
+ * image loading requests that get cancelled on cursor changes.
+ */
+ protected void setFragmentRootView(View fragmentRootView) {
+ mFragmentRootView = fragmentRootView;
+ }
+
+ protected void setDefaultFilterHeaderText(int resourceId) {
+ mDefaultFilterHeaderText = getContext().getResources().getText(resourceId);
+ }
+
+ @Override
+ protected ContactListItemView newView(
+ Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
+ final ContactListItemView view = new ContactListItemView(context, null);
+ view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
+ view.setAdjustSelectionBoundsEnabled(isAdjustSelectionBoundsEnabled());
+ return view;
+ }
+
+ @Override
+ protected void bindView(View itemView, int partition, Cursor cursor, int position) {
+ final ContactListItemView view = (ContactListItemView) itemView;
+ view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
+ bindWorkProfileIcon(view, partition);
+ }
+
+ @Override
+ protected View createPinnedSectionHeaderView(Context context, ViewGroup parent) {
+ return new ContactListPinnedHeaderView(context, null, parent);
+ }
+
+ @Override
+ protected void setPinnedSectionTitle(View pinnedHeaderView, String title) {
+ ((ContactListPinnedHeaderView) pinnedHeaderView).setSectionHeaderTitle(title);
+ }
+
+ protected void addPartitions() {
+ addPartition(createDefaultDirectoryPartition());
+ }
+
+ protected DirectoryPartition createDefaultDirectoryPartition() {
+ DirectoryPartition partition = new DirectoryPartition(true, true);
+ partition.setDirectoryId(Directory.DEFAULT);
+ partition.setDirectoryType(getContext().getString(R.string.contactsList));
+ partition.setPriorityDirectory(true);
+ partition.setPhotoSupported(true);
+ partition.setLabel(mDefaultFilterHeaderText.toString());
+ return partition;
+ }
+
+ /**
+ * Remove all directories after the default directory. This is typically used when contacts
+ * list screens are asked to exit the search mode and thus need to remove all remote directory
+ * results for the search.
+ *
+ * This code assumes that the default directory and directories before that should not be
+ * deleted (e.g. Join screen has "suggested contacts" directory before the default director,
+ * and we should not remove the directory).
+ */
+ public void removeDirectoriesAfterDefault() {
+ final int partitionCount = getPartitionCount();
+ for (int i = partitionCount - 1; i >= 0; i--) {
+ final Partition partition = getPartition(i);
+ if ((partition instanceof DirectoryPartition)
+ && ((DirectoryPartition) partition).getDirectoryId() == Directory.DEFAULT) {
+ break;
+ } else {
+ removePartition(i);
+ }
+ }
+ }
+
+ protected int getPartitionByDirectoryId(long id) {
+ int count = getPartitionCount();
+ for (int i = 0; i < count; i++) {
+ Partition partition = getPartition(i);
+ if (partition instanceof DirectoryPartition) {
+ if (((DirectoryPartition)partition).getDirectoryId() == id) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ protected DirectoryPartition getDirectoryById(long id) {
+ int count = getPartitionCount();
+ for (int i = 0; i < count; i++) {
+ Partition partition = getPartition(i);
+ if (partition instanceof DirectoryPartition) {
+ final DirectoryPartition directoryPartition = (DirectoryPartition) partition;
+ if (directoryPartition.getDirectoryId() == id) {
+ return directoryPartition;
+ }
+ }
+ }
+ return null;
+ }
+
+ public abstract String getContactDisplayName(int position);
+ public abstract void configureLoader(CursorLoader loader, long directoryId);
+
+ /**
+ * Marks all partitions as "loading"
+ */
+ public void onDataReload() {
+ boolean notify = false;
+ int count = getPartitionCount();
+ for (int i = 0; i < count; i++) {
+ Partition partition = getPartition(i);
+ if (partition instanceof DirectoryPartition) {
+ DirectoryPartition directoryPartition = (DirectoryPartition)partition;
+ if (!directoryPartition.isLoading()) {
+ notify = true;
+ }
+ directoryPartition.setStatus(DirectoryPartition.STATUS_NOT_LOADED);
+ }
+ }
+ if (notify) {
+ notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void clearPartitions() {
+ int count = getPartitionCount();
+ for (int i = 0; i < count; i++) {
+ Partition partition = getPartition(i);
+ if (partition instanceof DirectoryPartition) {
+ DirectoryPartition directoryPartition = (DirectoryPartition)partition;
+ directoryPartition.setStatus(DirectoryPartition.STATUS_NOT_LOADED);
+ }
+ }
+ super.clearPartitions();
+ }
+
+ public boolean isSearchMode() {
+ return mSearchMode;
+ }
+
+ public void setSearchMode(boolean flag) {
+ mSearchMode = flag;
+ }
+
+ public String getQueryString() {
+ return mQueryString;
+ }
+
+ public void setQueryString(String queryString) {
+ mQueryString = queryString;
+ if (TextUtils.isEmpty(queryString)) {
+ mUpperCaseQueryString = null;
+ } else {
+ mUpperCaseQueryString = SearchUtil
+ .cleanStartAndEndOfSearchQuery(queryString.toUpperCase()) ;
+ }
+ }
+
+ public String getUpperCaseQueryString() {
+ return mUpperCaseQueryString;
+ }
+
+ public int getDirectorySearchMode() {
+ return mDirectorySearchMode;
+ }
+
+ public void setDirectorySearchMode(int mode) {
+ mDirectorySearchMode = mode;
+ }
+
+ public int getDirectoryResultLimit() {
+ return mDirectoryResultLimit;
+ }
+
+ public int getDirectoryResultLimit(DirectoryPartition directoryPartition) {
+ final int limit = directoryPartition.getResultLimit();
+ return limit == DirectoryPartition.RESULT_LIMIT_DEFAULT ? mDirectoryResultLimit : limit;
+ }
+
+ public void setDirectoryResultLimit(int limit) {
+ this.mDirectoryResultLimit = limit;
+ }
+
+ public int getContactNameDisplayOrder() {
+ return mDisplayOrder;
+ }
+
+ public void setContactNameDisplayOrder(int displayOrder) {
+ mDisplayOrder = displayOrder;
+ }
+
+ public int getSortOrder() {
+ return mSortOrder;
+ }
+
+ public void setSortOrder(int sortOrder) {
+ mSortOrder = sortOrder;
+ }
+
+ public void setPhotoLoader(ContactPhotoManager photoLoader) {
+ mPhotoLoader = photoLoader;
+ }
+
+ protected ContactPhotoManager getPhotoLoader() {
+ return mPhotoLoader;
+ }
+
+ public boolean getDisplayPhotos() {
+ return mDisplayPhotos;
+ }
+
+ public void setDisplayPhotos(boolean displayPhotos) {
+ mDisplayPhotos = displayPhotos;
+ }
+
+ public boolean getCircularPhotos() {
+ return mCircularPhotos;
+ }
+
+ public void setCircularPhotos(boolean circularPhotos) {
+ mCircularPhotos = circularPhotos;
+ }
+
+ public boolean isEmptyListEnabled() {
+ return mEmptyListEnabled;
+ }
+
+ public void setEmptyListEnabled(boolean flag) {
+ mEmptyListEnabled = flag;
+ }
+
+ public boolean isSelectionVisible() {
+ return mSelectionVisible;
+ }
+
+ public void setSelectionVisible(boolean flag) {
+ this.mSelectionVisible = flag;
+ }
+
+ public boolean isQuickContactEnabled() {
+ return mQuickContactEnabled;
+ }
+
+ public void setQuickContactEnabled(boolean quickContactEnabled) {
+ mQuickContactEnabled = quickContactEnabled;
+ }
+
+ public boolean isAdjustSelectionBoundsEnabled() {
+ return mAdjustSelectionBoundsEnabled;
+ }
+
+ public void setAdjustSelectionBoundsEnabled(boolean enabled) {
+ mAdjustSelectionBoundsEnabled = enabled;
+ }
+
+ public boolean shouldIncludeFavorites() {
+ return mIncludeFavorites;
+ }
+
+ public void setIncludeFavorites(boolean includeFavorites) {
+ mIncludeFavorites = includeFavorites;
+ }
+
+ public void setFavoritesSectionHeader(int numberOfFavorites) {
+ if (mIncludeFavorites) {
+ mNumberOfFavorites = numberOfFavorites;
+ setSectionHeader(R.string.star_sign, numberOfFavorites);
+ }
+ }
+
+ public int getNumberOfFavorites() {
+ return mNumberOfFavorites;
+ }
+
+ private void setSectionHeader(int resId, int numberOfItems) {
+ SectionIndexer indexer = getIndexer();
+ if (indexer != null) {
+ ((ContactsSectionIndexer) indexer).setProfileAndFavoritesHeader(
+ getContext().getString(resId), numberOfItems);
+ }
+ }
+
+ public void setDarkTheme(boolean value) {
+ mDarkTheme = value;
+ }
+
+ /**
+ * Updates partitions according to the directory meta-data contained in the supplied
+ * cursor.
+ */
+ public void changeDirectories(Cursor cursor) {
+ if (cursor.getCount() == 0) {
+ // Directory table must have at least local directory, without which this adapter will
+ // enter very weird state.
+ Log.e(TAG, "Directory search loader returned an empty cursor, which implies we have " +
+ "no directory entries.", new RuntimeException());
+ return;
+ }
+ HashSet<Long> directoryIds = new HashSet<Long>();
+
+ int idColumnIndex = cursor.getColumnIndex(Directory._ID);
+ int directoryTypeColumnIndex = cursor.getColumnIndex(DirectoryListLoader.DIRECTORY_TYPE);
+ int displayNameColumnIndex = cursor.getColumnIndex(Directory.DISPLAY_NAME);
+ int photoSupportColumnIndex = cursor.getColumnIndex(Directory.PHOTO_SUPPORT);
+
+ // TODO preserve the order of partition to match those of the cursor
+ // Phase I: add new directories
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ long id = cursor.getLong(idColumnIndex);
+ directoryIds.add(id);
+ if (getPartitionByDirectoryId(id) == -1) {
+ DirectoryPartition partition = new DirectoryPartition(false, true);
+ partition.setDirectoryId(id);
+ if (DirectoryCompat.isRemoteDirectoryId(id)) {
+ if (DirectoryCompat.isEnterpriseDirectoryId(id)) {
+ partition.setLabel(mContext.getString(R.string.directory_search_label_work));
+ } else {
+ partition.setLabel(mContext.getString(R.string.directory_search_label));
+ }
+ } else {
+ if (DirectoryCompat.isEnterpriseDirectoryId(id)) {
+ partition.setLabel(mContext.getString(R.string.list_filter_phones_work));
+ } else {
+ partition.setLabel(mDefaultFilterHeaderText.toString());
+ }
+ }
+ partition.setDirectoryType(cursor.getString(directoryTypeColumnIndex));
+ partition.setDisplayName(cursor.getString(displayNameColumnIndex));
+ int photoSupport = cursor.getInt(photoSupportColumnIndex);
+ partition.setPhotoSupported(photoSupport == Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY
+ || photoSupport == Directory.PHOTO_SUPPORT_FULL);
+ addPartition(partition);
+ }
+ }
+
+ // Phase II: remove deleted directories
+ int count = getPartitionCount();
+ for (int i = count; --i >= 0; ) {
+ Partition partition = getPartition(i);
+ if (partition instanceof DirectoryPartition) {
+ long id = ((DirectoryPartition)partition).getDirectoryId();
+ if (!directoryIds.contains(id)) {
+ removePartition(i);
+ }
+ }
+ }
+
+ invalidate();
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void changeCursor(int partitionIndex, Cursor cursor) {
+ if (partitionIndex >= getPartitionCount()) {
+ // There is no partition for this data
+ return;
+ }
+
+ Partition partition = getPartition(partitionIndex);
+ if (partition instanceof DirectoryPartition) {
+ ((DirectoryPartition)partition).setStatus(DirectoryPartition.STATUS_LOADED);
+ }
+
+ if (mDisplayPhotos && mPhotoLoader != null && isPhotoSupported(partitionIndex)) {
+ mPhotoLoader.refreshCache();
+ }
+
+ super.changeCursor(partitionIndex, cursor);
+
+ if (isSectionHeaderDisplayEnabled() && partitionIndex == getIndexedPartition()) {
+ updateIndexer(cursor);
+ }
+
+ // When the cursor changes, cancel any pending asynchronous photo loads.
+ mPhotoLoader.cancelPendingRequests(mFragmentRootView);
+ }
+
+ public void changeCursor(Cursor cursor) {
+ changeCursor(0, cursor);
+ }
+
+ /**
+ * Updates the indexer, which is used to produce section headers.
+ */
+ private void updateIndexer(Cursor cursor) {
+ if (cursor == null || cursor.isClosed()) {
+ setIndexer(null);
+ return;
+ }
+
+ Bundle bundle = cursor.getExtras();
+ if (bundle.containsKey(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES) &&
+ bundle.containsKey(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS)) {
+ String sections[] =
+ bundle.getStringArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
+ int counts[] = bundle.getIntArray(
+ Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
+
+ if (getExtraStartingSection()) {
+ // Insert an additional unnamed section at the top of the list.
+ String allSections[] = new String[sections.length + 1];
+ int allCounts[] = new int[counts.length + 1];
+ for (int i = 0; i < sections.length; i++) {
+ allSections[i + 1] = sections[i];
+ allCounts[i + 1] = counts[i];
+ }
+ allCounts[0] = 1;
+ allSections[0] = "";
+ setIndexer(new ContactsSectionIndexer(allSections, allCounts));
+ } else {
+ setIndexer(new ContactsSectionIndexer(sections, counts));
+ }
+ } else {
+ setIndexer(null);
+ }
+ }
+
+ protected boolean getExtraStartingSection() {
+ return false;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ // We need a separate view type for each item type, plus another one for
+ // each type with header, plus one for "other".
+ return getItemViewTypeCount() * 2 + 1;
+ }
+
+ @Override
+ public int getItemViewType(int partitionIndex, int position) {
+ int type = super.getItemViewType(partitionIndex, position);
+ if (isSectionHeaderDisplayEnabled() && partitionIndex == getIndexedPartition()) {
+ Placement placement = getItemPlacementInSection(position);
+ return placement.firstInSection ? type : getItemViewTypeCount() + type;
+ } else {
+ return type;
+ }
+ }
+
+ @Override
+ public boolean isEmpty() {
+ // TODO
+// if (contactsListActivity.mProviderStatus != ProviderStatus.STATUS_NORMAL) {
+// return true;
+// }
+
+ if (!mEmptyListEnabled) {
+ return false;
+ } else if (isSearchMode()) {
+ return TextUtils.isEmpty(getQueryString());
+ } else {
+ return super.isEmpty();
+ }
+ }
+
+ public boolean isLoading() {
+ int count = getPartitionCount();
+ for (int i = 0; i < count; i++) {
+ Partition partition = getPartition(i);
+ if (partition instanceof DirectoryPartition
+ && ((DirectoryPartition) partition).isLoading()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean areAllPartitionsEmpty() {
+ int count = getPartitionCount();
+ for (int i = 0; i < count; i++) {
+ if (!isPartitionEmpty(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Changes visibility parameters for the default directory partition.
+ */
+ public void configureDefaultPartition(boolean showIfEmpty, boolean hasHeader) {
+ int defaultPartitionIndex = -1;
+ int count = getPartitionCount();
+ for (int i = 0; i < count; i++) {
+ Partition partition = getPartition(i);
+ if (partition instanceof DirectoryPartition &&
+ ((DirectoryPartition)partition).getDirectoryId() == Directory.DEFAULT) {
+ defaultPartitionIndex = i;
+ break;
+ }
+ }
+ if (defaultPartitionIndex != -1) {
+ setShowIfEmpty(defaultPartitionIndex, showIfEmpty);
+ setHasHeader(defaultPartitionIndex, hasHeader);
+ }
+ }
+
+ @Override
+ protected View newHeaderView(Context context, int partition, Cursor cursor,
+ ViewGroup parent) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ View view = inflater.inflate(R.layout.directory_header, parent, false);
+ if (!getPinnedPartitionHeadersEnabled()) {
+ // If the headers are unpinned, there is no need for their background
+ // color to be non-transparent. Setting this transparent reduces maintenance for
+ // non-pinned headers. We don't need to bother synchronizing the activity's
+ // background color with the header background color.
+ view.setBackground(null);
+ }
+ return view;
+ }
+
+ protected void bindWorkProfileIcon(final ContactListItemView view, int partitionId) {
+ final Partition partition = getPartition(partitionId);
+ if (partition instanceof DirectoryPartition) {
+ final DirectoryPartition directoryPartition = (DirectoryPartition) partition;
+ final long directoryId = directoryPartition.getDirectoryId();
+ final long userType = ContactsUtils.determineUserType(directoryId, null);
+ view.setWorkProfileIconEnabled(userType == ContactsUtils.USER_TYPE_WORK);
+ }
+ }
+
+ @Override
+ protected void bindHeaderView(View view, int partitionIndex, Cursor cursor) {
+ Partition partition = getPartition(partitionIndex);
+ if (!(partition instanceof DirectoryPartition)) {
+ return;
+ }
+
+ DirectoryPartition directoryPartition = (DirectoryPartition)partition;
+ long directoryId = directoryPartition.getDirectoryId();
+ TextView labelTextView = (TextView)view.findViewById(R.id.label);
+ TextView displayNameTextView = (TextView)view.findViewById(R.id.display_name);
+ labelTextView.setText(directoryPartition.getLabel());
+ if (!DirectoryCompat.isRemoteDirectoryId(directoryId)) {
+ displayNameTextView.setText(null);
+ } else {
+ String directoryName = directoryPartition.getDisplayName();
+ String displayName = !TextUtils.isEmpty(directoryName)
+ ? directoryName
+ : directoryPartition.getDirectoryType();
+ displayNameTextView.setText(displayName);
+ }
+
+ final Resources res = getContext().getResources();
+ final int headerPaddingTop = partitionIndex == 1 && getPartition(0).isEmpty()?
+ 0 : res.getDimensionPixelOffset(R.dimen.directory_header_extra_top_padding);
+ // There should be no extra padding at the top of the first directory header
+ view.setPaddingRelative(view.getPaddingStart(), headerPaddingTop, view.getPaddingEnd(),
+ view.getPaddingBottom());
+ }
+
+ // Default implementation simply returns number of rows in the cursor.
+ // Broken out into its own routine so can be overridden by child classes
+ // for eg number of unique contacts for a phone list.
+ protected int getResultCount(Cursor cursor) {
+ return cursor == null ? 0 : cursor.getCount();
+ }
+
+ // TODO: fix PluralRules to handle zero correctly and use Resources.getQuantityText directly
+ public String getQuantityText(int count, int zeroResourceId, int pluralResourceId) {
+ if (count == 0) {
+ return getContext().getString(zeroResourceId);
+ } else {
+ String format = getContext().getResources()
+ .getQuantityText(pluralResourceId, count).toString();
+ return String.format(format, count);
+ }
+ }
+
+ public boolean isPhotoSupported(int partitionIndex) {
+ Partition partition = getPartition(partitionIndex);
+ if (partition instanceof DirectoryPartition) {
+ return ((DirectoryPartition) partition).isPhotoSupported();
+ }
+ return true;
+ }
+
+ /**
+ * Returns the currently selected filter.
+ */
+ public ContactListFilter getFilter() {
+ return mFilter;
+ }
+
+ public void setFilter(ContactListFilter filter) {
+ mFilter = filter;
+ }
+
+ // TODO: move sharable logic (bindXX() methods) to here with extra arguments
+
+ /**
+ * Loads the photo for the quick contact view and assigns the contact uri.
+ * @param photoIdColumn Index of the photo id column
+ * @param photoUriColumn Index of the photo uri column. Optional: Can be -1
+ * @param contactIdColumn Index of the contact id column
+ * @param lookUpKeyColumn Index of the lookup key column
+ * @param displayNameColumn Index of the display name column
+ */
+ protected void bindQuickContact(final ContactListItemView view, int partitionIndex,
+ Cursor cursor, int photoIdColumn, int photoUriColumn, int contactIdColumn,
+ int lookUpKeyColumn, int displayNameColumn) {
+ long photoId = 0;
+ if (!cursor.isNull(photoIdColumn)) {
+ photoId = cursor.getLong(photoIdColumn);
+ }
+
+ QuickContactBadge quickContact = view.getQuickContact();
+ quickContact.assignContactUri(
+ getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn));
+ if (CompatUtils.hasPrioritizedMimeType()) {
+ // The Contacts app never uses the QuickContactBadge. Therefore, it is safe to assume
+ // that only Dialer will use this QuickContact badge. This means prioritizing the phone
+ // mimetype here is reasonable.
+ quickContact.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
+ }
+
+ if (photoId != 0 || photoUriColumn == -1) {
+ getPhotoLoader().loadThumbnail(quickContact, photoId, mDarkTheme, mCircularPhotos,
+ null);
+ } else {
+ final String photoUriString = cursor.getString(photoUriColumn);
+ final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
+ DefaultImageRequest request = null;
+ if (photoUri == null) {
+ request = getDefaultImageRequestFromCursor(cursor, displayNameColumn,
+ lookUpKeyColumn);
+ }
+ getPhotoLoader().loadPhoto(quickContact, photoUri, -1, mDarkTheme, mCircularPhotos,
+ request);
+ }
+
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ // Whenever bindViewId() is called, the values passed into setId() are stable or
+ // stable-ish. For example, when one contact is modified we don't expect a second
+ // contact's Contact._ID values to change.
+ return true;
+ }
+
+ protected void bindViewId(final ContactListItemView view, Cursor cursor, int idColumn) {
+ // Set a semi-stable id, so that talkback won't get confused when the list gets
+ // refreshed. There is little harm in inserting the same ID twice.
+ long contactId = cursor.getLong(idColumn);
+ view.setId((int) (contactId % Integer.MAX_VALUE));
+
+ }
+
+ protected Uri getContactUri(int partitionIndex, Cursor cursor,
+ int contactIdColumn, int lookUpKeyColumn) {
+ long contactId = cursor.getLong(contactIdColumn);
+ String lookupKey = cursor.getString(lookUpKeyColumn);
+ long directoryId = ((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId();
+ Uri uri = Contacts.getLookupUri(contactId, lookupKey);
+ if (uri != null && directoryId != Directory.DEFAULT) {
+ uri = uri.buildUpon().appendQueryParameter(
+ ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
+ }
+ return uri;
+ }
+
+ /**
+ * Retrieves the lookup key and display name from a cursor, and returns a
+ * {@link DefaultImageRequest} containing these contact details
+ *
+ * @param cursor Contacts cursor positioned at the current row to retrieve contact details for
+ * @param displayNameColumn Column index of the display name
+ * @param lookupKeyColumn Column index of the lookup key
+ * @return {@link DefaultImageRequest} with the displayName and identifier fields set to the
+ * display name and lookup key of the contact.
+ */
+ public DefaultImageRequest getDefaultImageRequestFromCursor(Cursor cursor,
+ int displayNameColumn, int lookupKeyColumn) {
+ final String displayName = cursor.getString(displayNameColumn);
+ final String lookupKey = cursor.getString(lookupKeyColumn);
+ return new DefaultImageRequest(displayName, lookupKey, mCircularPhotos);
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactEntryListFragment.java b/src/com/android/contacts/common/list/ContactEntryListFragment.java
new file mode 100644
index 0000000..0c72d68
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactEntryListFragment.java
@@ -0,0 +1,987 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.LoaderManager;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Intent;
+import android.content.Loader;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Parcelable;
+import android.provider.ContactsContract.Directory;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.AdapterView.OnItemLongClickListener;
+import android.widget.ListView;
+
+import com.android.common.widget.CompositeCursorAdapter.Partition;
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.logging.ListEvent.ActionType;
+import com.android.contacts.common.logging.Logger;
+import com.android.contacts.common.preference.ContactsPreferences;
+
+import java.util.Locale;
+
+/**
+ * Common base class for various contact-related list fragments.
+ */
+public abstract class ContactEntryListFragment<T extends ContactEntryListAdapter>
+ extends Fragment
+ implements OnItemClickListener, OnScrollListener, OnFocusChangeListener, OnTouchListener,
+ OnItemLongClickListener, LoaderCallbacks<Cursor> {
+ private static final String TAG = "ContactEntryListFragment";
+
+ // TODO: Make this protected. This should not be used from the PeopleActivity but
+ // instead use the new startActivityWithResultFromFragment API
+ public static final int ACTIVITY_REQUEST_CODE_PICKER = 1;
+
+ private static final String KEY_LIST_STATE = "liststate";
+ private static final String KEY_SECTION_HEADER_DISPLAY_ENABLED = "sectionHeaderDisplayEnabled";
+ private static final String KEY_PHOTO_LOADER_ENABLED = "photoLoaderEnabled";
+ private static final String KEY_QUICK_CONTACT_ENABLED = "quickContactEnabled";
+ private static final String KEY_ADJUST_SELECTION_BOUNDS_ENABLED =
+ "adjustSelectionBoundsEnabled";
+ private static final String KEY_SEARCH_MODE = "searchMode";
+ private static final String KEY_DISPLAY_DIRECTORY_HEADER = "displayDirectoryHeader";
+ private static final String KEY_VISIBLE_SCROLLBAR_ENABLED = "visibleScrollbarEnabled";
+ private static final String KEY_SCROLLBAR_POSITION = "scrollbarPosition";
+ private static final String KEY_QUERY_STRING = "queryString";
+ private static final String KEY_DIRECTORY_SEARCH_MODE = "directorySearchMode";
+ private static final String KEY_SELECTION_VISIBLE = "selectionVisible";
+ private static final String KEY_REQUEST = "request";
+ private static final String KEY_DARK_THEME = "darkTheme";
+ private static final String KEY_LEGACY_COMPATIBILITY = "legacyCompatibility";
+ private static final String KEY_DIRECTORY_RESULT_LIMIT = "directoryResultLimit";
+ private static final String KEY_LOGS_LIST_EVENTS = "logsListEvents";
+ private static final String KEY_DATA_LOADED = "dataLoaded";
+
+ private static final String DIRECTORY_ID_ARG_KEY = "directoryId";
+
+ private static final int DIRECTORY_LOADER_ID = -1;
+
+ private static final int DIRECTORY_SEARCH_DELAY_MILLIS = 300;
+ private static final int DIRECTORY_SEARCH_MESSAGE = 1;
+
+ private static final int DEFAULT_DIRECTORY_RESULT_LIMIT = 20;
+
+ private boolean mSectionHeaderDisplayEnabled;
+ private boolean mPhotoLoaderEnabled;
+ private boolean mQuickContactEnabled = true;
+ private boolean mAdjustSelectionBoundsEnabled = true;
+ private boolean mIncludeFavorites;
+ private boolean mSearchMode;
+ private boolean mDisplayDirectoryHeader = true;
+ private boolean mVisibleScrollbarEnabled;
+ private boolean mShowEmptyListForEmptyQuery;
+ private int mVerticalScrollbarPosition = getDefaultVerticalScrollbarPosition();
+ private String mQueryString;
+ private int mDirectorySearchMode = DirectoryListLoader.SEARCH_MODE_NONE;
+ private boolean mSelectionVisible;
+ private boolean mLegacyCompatibility;
+ // Whether we should log list LOAD events. It may be modified when list filter is changed.
+ private boolean mLogListEvents = true;
+ // Whether data has been loaded ever. It will stay true once it's set to true in the lifecycle.
+ // We use this flag to log LOAD events when the activity/fragment is initialized.
+ private boolean mDataLoaded;
+
+ private boolean mEnabled = true;
+
+ private T mAdapter;
+ private View mView;
+ private ListView mListView;
+
+ /**
+ * Used to save the scrolling state of the list when the fragment is not recreated.
+ */
+ private int mListViewTopIndex;
+ private int mListViewTopOffset;
+
+ /**
+ * Used for keeping track of the scroll state of the list.
+ */
+ private Parcelable mListState;
+
+ /**
+ * The type of the contacts list.
+ */
+ private int mListType;
+
+ private int mDisplayOrder;
+ private int mSortOrder;
+ private int mDirectoryResultLimit = DEFAULT_DIRECTORY_RESULT_LIMIT;
+
+ private ContactPhotoManager mPhotoManager;
+ private ContactsPreferences mContactsPrefs;
+
+ private boolean mForceLoad;
+
+ private boolean mDarkTheme;
+
+ private static final int STATUS_NOT_LOADED = 0;
+ private static final int STATUS_LOADING = 1;
+ private static final int STATUS_LOADED = 2;
+
+ private int mDirectoryListStatus = STATUS_NOT_LOADED;
+
+ /**
+ * Indicates whether we are doing the initial complete load of data (false) or
+ * a refresh caused by a change notification (true)
+ */
+ private boolean mLoadPriorityDirectoriesOnly;
+
+ private Context mContext;
+
+ private LoaderManager mLoaderManager;
+
+ private Handler mDelayedDirectorySearchHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == DIRECTORY_SEARCH_MESSAGE) {
+ loadDirectoryPartition(msg.arg1, (DirectoryPartition) msg.obj);
+ }
+ }
+ };
+ private int defaultVerticalScrollbarPosition;
+
+ protected abstract View inflateView(LayoutInflater inflater, ViewGroup container);
+ protected abstract T createListAdapter();
+
+ /**
+ * @param position Please note that the position is already adjusted for
+ * header views, so "0" means the first list item below header
+ * views.
+ */
+ protected abstract void onItemClick(int position, long id);
+
+ /**
+ * @param position Please note that the position is already adjusted for
+ * header views, so "0" means the first list item below header
+ * views.
+ */
+ protected boolean onItemLongClick(int position, long id) {
+ return false;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ setContext(activity);
+ setLoaderManager(super.getLoaderManager());
+ }
+
+ /**
+ * Sets a context for the fragment in the unit test environment.
+ */
+ public void setContext(Context context) {
+ mContext = context;
+ configurePhotoLoader();
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public void setEnabled(boolean enabled) {
+ if (mEnabled != enabled) {
+ mEnabled = enabled;
+ if (mAdapter != null) {
+ if (mEnabled) {
+ reloadData();
+ } else {
+ mAdapter.clearPartitions();
+ }
+ }
+ }
+ }
+
+ /**
+ * Overrides a loader manager for use in unit tests.
+ */
+ public void setLoaderManager(LoaderManager loaderManager) {
+ mLoaderManager = loaderManager;
+ }
+
+ @Override
+ public LoaderManager getLoaderManager() {
+ return mLoaderManager;
+ }
+
+ public T getAdapter() {
+ return mAdapter;
+ }
+
+ @Override
+ public View getView() {
+ return mView;
+ }
+
+ public ListView getListView() {
+ return mListView;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(KEY_SECTION_HEADER_DISPLAY_ENABLED, mSectionHeaderDisplayEnabled);
+ outState.putBoolean(KEY_PHOTO_LOADER_ENABLED, mPhotoLoaderEnabled);
+ outState.putBoolean(KEY_QUICK_CONTACT_ENABLED, mQuickContactEnabled);
+ outState.putBoolean(KEY_ADJUST_SELECTION_BOUNDS_ENABLED, mAdjustSelectionBoundsEnabled);
+ outState.putBoolean(KEY_SEARCH_MODE, mSearchMode);
+ outState.putBoolean(KEY_DISPLAY_DIRECTORY_HEADER, mDisplayDirectoryHeader);
+ outState.putBoolean(KEY_VISIBLE_SCROLLBAR_ENABLED, mVisibleScrollbarEnabled);
+ outState.putInt(KEY_SCROLLBAR_POSITION, mVerticalScrollbarPosition);
+ outState.putInt(KEY_DIRECTORY_SEARCH_MODE, mDirectorySearchMode);
+ outState.putBoolean(KEY_SELECTION_VISIBLE, mSelectionVisible);
+ outState.putBoolean(KEY_LEGACY_COMPATIBILITY, mLegacyCompatibility);
+ outState.putString(KEY_QUERY_STRING, mQueryString);
+ outState.putInt(KEY_DIRECTORY_RESULT_LIMIT, mDirectoryResultLimit);
+ outState.putBoolean(KEY_DARK_THEME, mDarkTheme);
+ outState.putBoolean(KEY_LOGS_LIST_EVENTS, mLogListEvents);
+ outState.putBoolean(KEY_DATA_LOADED, mDataLoaded);
+
+ if (mListView != null) {
+ outState.putParcelable(KEY_LIST_STATE, mListView.onSaveInstanceState());
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedState) {
+ super.onCreate(savedState);
+ restoreSavedState(savedState);
+ mAdapter = createListAdapter();
+ mContactsPrefs = new ContactsPreferences(mContext);
+ }
+
+ public void restoreSavedState(Bundle savedState) {
+ if (savedState == null) {
+ return;
+ }
+
+ mSectionHeaderDisplayEnabled = savedState.getBoolean(KEY_SECTION_HEADER_DISPLAY_ENABLED);
+ mPhotoLoaderEnabled = savedState.getBoolean(KEY_PHOTO_LOADER_ENABLED);
+ mQuickContactEnabled = savedState.getBoolean(KEY_QUICK_CONTACT_ENABLED);
+ mAdjustSelectionBoundsEnabled = savedState.getBoolean(KEY_ADJUST_SELECTION_BOUNDS_ENABLED);
+ mSearchMode = savedState.getBoolean(KEY_SEARCH_MODE);
+ mDisplayDirectoryHeader = savedState.getBoolean(KEY_DISPLAY_DIRECTORY_HEADER);
+ mVisibleScrollbarEnabled = savedState.getBoolean(KEY_VISIBLE_SCROLLBAR_ENABLED);
+ mVerticalScrollbarPosition = savedState.getInt(KEY_SCROLLBAR_POSITION);
+ mDirectorySearchMode = savedState.getInt(KEY_DIRECTORY_SEARCH_MODE);
+ mSelectionVisible = savedState.getBoolean(KEY_SELECTION_VISIBLE);
+ mLegacyCompatibility = savedState.getBoolean(KEY_LEGACY_COMPATIBILITY);
+ mQueryString = savedState.getString(KEY_QUERY_STRING);
+ mDirectoryResultLimit = savedState.getInt(KEY_DIRECTORY_RESULT_LIMIT);
+ mDarkTheme = savedState.getBoolean(KEY_DARK_THEME);
+
+ // Retrieve list state. This will be applied in onLoadFinished
+ mListState = savedState.getParcelable(KEY_LIST_STATE);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ mContactsPrefs.registerChangeListener(mPreferencesChangeListener);
+
+ mForceLoad = loadPreferences();
+
+ mDirectoryListStatus = STATUS_NOT_LOADED;
+ mLoadPriorityDirectoriesOnly = true;
+
+ startLoading();
+ }
+
+ protected void startLoading() {
+ if (mAdapter == null) {
+ // The method was called before the fragment was started
+ return;
+ }
+
+ configureAdapter();
+ int partitionCount = mAdapter.getPartitionCount();
+ for (int i = 0; i < partitionCount; i++) {
+ Partition partition = mAdapter.getPartition(i);
+ if (partition instanceof DirectoryPartition) {
+ DirectoryPartition directoryPartition = (DirectoryPartition)partition;
+ if (directoryPartition.getStatus() == DirectoryPartition.STATUS_NOT_LOADED) {
+ if (directoryPartition.isPriorityDirectory() || !mLoadPriorityDirectoriesOnly) {
+ startLoadingDirectoryPartition(i);
+ }
+ }
+ } else {
+ getLoaderManager().initLoader(i, null, this);
+ }
+ }
+
+ // Next time this method is called, we should start loading non-priority directories
+ mLoadPriorityDirectoriesOnly = false;
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ if (id == DIRECTORY_LOADER_ID) {
+ DirectoryListLoader loader = new DirectoryListLoader(mContext);
+ loader.setDirectorySearchMode(mAdapter.getDirectorySearchMode());
+ loader.setLocalInvisibleDirectoryEnabled(
+ ContactEntryListAdapter.LOCAL_INVISIBLE_DIRECTORY_ENABLED);
+ return loader;
+ } else {
+ CursorLoader loader = createCursorLoader(mContext);
+ long directoryId = args != null && args.containsKey(DIRECTORY_ID_ARG_KEY)
+ ? args.getLong(DIRECTORY_ID_ARG_KEY)
+ : Directory.DEFAULT;
+ mAdapter.configureLoader(loader, directoryId);
+ return loader;
+ }
+ }
+
+ public CursorLoader createCursorLoader(Context context) {
+ return new CursorLoader(context, null, null, null, null, null) {
+ @Override
+ protected Cursor onLoadInBackground() {
+ try {
+ return super.onLoadInBackground();
+ } catch (RuntimeException e) {
+ // We don't even know what the projection should be, so no point trying to
+ // return an empty MatrixCursor with the correct projection here.
+ Log.w(TAG, "RuntimeException while trying to query ContactsProvider.");
+ return null;
+ }
+ }
+ };
+ }
+
+ private void startLoadingDirectoryPartition(int partitionIndex) {
+ DirectoryPartition partition = (DirectoryPartition)mAdapter.getPartition(partitionIndex);
+ partition.setStatus(DirectoryPartition.STATUS_LOADING);
+ long directoryId = partition.getDirectoryId();
+ if (mForceLoad) {
+ if (directoryId == Directory.DEFAULT) {
+ loadDirectoryPartition(partitionIndex, partition);
+ } else {
+ loadDirectoryPartitionDelayed(partitionIndex, partition);
+ }
+ } else {
+ Bundle args = new Bundle();
+ args.putLong(DIRECTORY_ID_ARG_KEY, directoryId);
+ getLoaderManager().initLoader(partitionIndex, args, this);
+ }
+ }
+
+ /**
+ * Queues up a delayed request to search the specified directory. Since
+ * directory search will likely introduce a lot of network traffic, we want
+ * to wait for a pause in the user's typing before sending a directory request.
+ */
+ private void loadDirectoryPartitionDelayed(int partitionIndex, DirectoryPartition partition) {
+ mDelayedDirectorySearchHandler.removeMessages(DIRECTORY_SEARCH_MESSAGE, partition);
+ Message msg = mDelayedDirectorySearchHandler.obtainMessage(
+ DIRECTORY_SEARCH_MESSAGE, partitionIndex, 0, partition);
+ mDelayedDirectorySearchHandler.sendMessageDelayed(msg, DIRECTORY_SEARCH_DELAY_MILLIS);
+ }
+
+ /**
+ * Loads the directory partition.
+ */
+ protected void loadDirectoryPartition(int partitionIndex, DirectoryPartition partition) {
+ Bundle args = new Bundle();
+ args.putLong(DIRECTORY_ID_ARG_KEY, partition.getDirectoryId());
+ getLoaderManager().restartLoader(partitionIndex, args, this);
+ }
+
+ /**
+ * Cancels all queued directory loading requests.
+ */
+ private void removePendingDirectorySearchRequests() {
+ mDelayedDirectorySearchHandler.removeMessages(DIRECTORY_SEARCH_MESSAGE);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ if (!mEnabled) {
+ return;
+ }
+
+ getListView().setVisibility(View.VISIBLE);
+ getView().setVisibility(View.VISIBLE);
+
+ int loaderId = loader.getId();
+ if (loaderId == DIRECTORY_LOADER_ID) {
+ mDirectoryListStatus = STATUS_LOADED;
+ mAdapter.changeDirectories(data);
+ startLoading();
+ } else {
+ onPartitionLoaded(loaderId, data);
+ if (isSearchMode()) {
+ int directorySearchMode = getDirectorySearchMode();
+ if (directorySearchMode != DirectoryListLoader.SEARCH_MODE_NONE) {
+ if (mDirectoryListStatus == STATUS_NOT_LOADED) {
+ mDirectoryListStatus = STATUS_LOADING;
+ getLoaderManager().initLoader(DIRECTORY_LOADER_ID, null, this);
+ } else {
+ startLoading();
+ }
+ }
+ } else {
+ maybeLogListEvent();
+ mDirectoryListStatus = STATUS_NOT_LOADED;
+ getLoaderManager().destroyLoader(DIRECTORY_LOADER_ID);
+ }
+ }
+ }
+
+ protected void maybeLogListEvent() {
+ if (!mDataLoaded || mLogListEvents) {
+ Logger.logListEvent(ActionType.LOAD, getListType(), getAdapter().getCount(),
+ /* clickedIndex */ -1, /* numSelected */ 0);
+ mLogListEvents = false;
+ mDataLoaded = true;
+ }
+ }
+
+ public void onLoaderReset(Loader<Cursor> loader) {
+ }
+
+ protected void onPartitionLoaded(int partitionIndex, Cursor data) {
+ if (partitionIndex >= mAdapter.getPartitionCount()) {
+ // When we get unsolicited data, ignore it. This could happen
+ // when we are switching from search mode to the default mode.
+ return;
+ }
+
+ mAdapter.changeCursor(partitionIndex, data);
+ setListHeader();
+
+ if (!isLoading()) {
+ completeRestoreInstanceState();
+ }
+ }
+
+ public boolean isLoading() {
+ if (mAdapter != null && mAdapter.isLoading()) {
+ return true;
+ }
+
+ if (isLoadingDirectoryList()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean isLoadingDirectoryList() {
+ return isSearchMode() && getDirectorySearchMode() != DirectoryListLoader.SEARCH_MODE_NONE
+ && (mDirectoryListStatus == STATUS_NOT_LOADED
+ || mDirectoryListStatus == STATUS_LOADING);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mContactsPrefs.unregisterChangeListener();
+ mAdapter.clearPartitions();
+ }
+
+ protected void reloadData() {
+ removePendingDirectorySearchRequests();
+ mAdapter.onDataReload();
+ mLoadPriorityDirectoriesOnly = true;
+ mForceLoad = true;
+ startLoading();
+ }
+
+ /**
+ * Shows a view at the top of the list.
+ */
+ protected void setListHeader() {}
+
+ /**
+ * Provides logic that dismisses this fragment. The default implementation
+ * does nothing.
+ */
+ protected void finish() {
+ }
+
+ public void setSectionHeaderDisplayEnabled(boolean flag) {
+ if (mSectionHeaderDisplayEnabled != flag) {
+ mSectionHeaderDisplayEnabled = flag;
+ if (mAdapter != null) {
+ mAdapter.setSectionHeaderDisplayEnabled(flag);
+ }
+ configureVerticalScrollbar();
+ }
+ }
+
+ public boolean isSectionHeaderDisplayEnabled() {
+ return mSectionHeaderDisplayEnabled;
+ }
+
+ public void setVisibleScrollbarEnabled(boolean flag) {
+ if (mVisibleScrollbarEnabled != flag) {
+ mVisibleScrollbarEnabled = flag;
+ configureVerticalScrollbar();
+ }
+ }
+
+ public boolean isVisibleScrollbarEnabled() {
+ return mVisibleScrollbarEnabled;
+ }
+
+ public void setVerticalScrollbarPosition(int position) {
+ if (mVerticalScrollbarPosition != position) {
+ mVerticalScrollbarPosition = position;
+ configureVerticalScrollbar();
+ }
+ }
+
+ private void configureVerticalScrollbar() {
+ boolean hasScrollbar = isVisibleScrollbarEnabled() && isSectionHeaderDisplayEnabled();
+
+ if (mListView != null) {
+ mListView.setFastScrollEnabled(hasScrollbar);
+ mListView.setVerticalScrollbarPosition(mVerticalScrollbarPosition);
+ mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
+ }
+ }
+
+ public void setPhotoLoaderEnabled(boolean flag) {
+ mPhotoLoaderEnabled = flag;
+ configurePhotoLoader();
+ }
+
+ public boolean isPhotoLoaderEnabled() {
+ return mPhotoLoaderEnabled;
+ }
+
+ /**
+ * Returns true if the list is supposed to visually highlight the selected item.
+ */
+ public boolean isSelectionVisible() {
+ return mSelectionVisible;
+ }
+
+ public void setSelectionVisible(boolean flag) {
+ this.mSelectionVisible = flag;
+ }
+
+ public void setQuickContactEnabled(boolean flag) {
+ this.mQuickContactEnabled = flag;
+ }
+
+ public void setAdjustSelectionBoundsEnabled(boolean flag) {
+ mAdjustSelectionBoundsEnabled = flag;
+ }
+
+ public void setIncludeFavorites(boolean flag) {
+ mIncludeFavorites = flag;
+ if (mAdapter != null) {
+ mAdapter.setIncludeFavorites(flag);
+ }
+ }
+
+ public void setDisplayDirectoryHeader(boolean flag) {
+ mDisplayDirectoryHeader = flag;
+ }
+
+ /**
+ * Enter/exit search mode. This is method is tightly related to the current query, and should
+ * only be called by {@link #setQueryString}.
+ *
+ * Also note this method doesn't call {@link #reloadData()}; {@link #setQueryString} does it.
+ */
+ protected void setSearchMode(boolean flag) {
+ if (mSearchMode != flag) {
+ mSearchMode = flag;
+ setSectionHeaderDisplayEnabled(!mSearchMode);
+
+ if (!flag) {
+ mDirectoryListStatus = STATUS_NOT_LOADED;
+ getLoaderManager().destroyLoader(DIRECTORY_LOADER_ID);
+ }
+
+ if (mAdapter != null) {
+ mAdapter.setSearchMode(flag);
+
+ mAdapter.clearPartitions();
+ if (!flag) {
+ // If we are switching from search to regular display, remove all directory
+ // partitions after default one, assuming they are remote directories which
+ // should be cleaned up on exiting the search mode.
+ mAdapter.removeDirectoriesAfterDefault();
+ }
+ mAdapter.configureDefaultPartition(false, shouldDisplayDirectoryHeader());
+ }
+
+ if (mListView != null) {
+ mListView.setFastScrollEnabled(!flag);
+ }
+ }
+ }
+
+ /**
+ * When not in search mode, directory header should always be hidden.
+ * When in search mode, directory header should be displayed when mDisplayDirectoryHeader is
+ * set to true. (mDisplayDirectoryHeader default value is true)
+ */
+ private boolean shouldDisplayDirectoryHeader() {
+ if (!mSearchMode) {
+ return false;
+ }
+ return mDisplayDirectoryHeader;
+ }
+
+ public final boolean isSearchMode() {
+ return mSearchMode;
+ }
+
+ public final String getQueryString() {
+ return mQueryString;
+ }
+
+ // TODO: the paramter delaySelection is not in use, and let's remove it.
+ public void setQueryString(String queryString, boolean delaySelection) {
+ if (!TextUtils.equals(mQueryString, queryString)) {
+ if (mShowEmptyListForEmptyQuery && mAdapter != null && mListView != null) {
+ if (TextUtils.isEmpty(mQueryString)) {
+ // Restore the adapter if the query used to be empty.
+ mListView.setAdapter(mAdapter);
+ } else if (TextUtils.isEmpty(queryString)) {
+ // Instantly clear the list view if the new query is empty.
+ mListView.setAdapter(null);
+ }
+ }
+
+ mQueryString = queryString;
+ setSearchMode(!TextUtils.isEmpty(mQueryString) || mShowEmptyListForEmptyQuery);
+
+ if (mAdapter != null) {
+ mAdapter.setQueryString(queryString);
+ reloadData();
+ }
+ }
+ }
+
+ public void setShowEmptyListForNullQuery(boolean show) {
+ mShowEmptyListForEmptyQuery = show;
+ }
+
+ public int getDirectoryLoaderId() {
+ return DIRECTORY_LOADER_ID;
+ }
+
+ public int getDirectorySearchMode() {
+ return mDirectorySearchMode;
+ }
+
+ public void setDirectorySearchMode(int mode) {
+ mDirectorySearchMode = mode;
+ }
+
+ public boolean isLegacyCompatibilityMode() {
+ return mLegacyCompatibility;
+ }
+
+ public void setLegacyCompatibilityMode(boolean flag) {
+ mLegacyCompatibility = flag;
+ }
+
+ protected int getContactNameDisplayOrder() {
+ return mDisplayOrder;
+ }
+
+ protected void setContactNameDisplayOrder(int displayOrder) {
+ mDisplayOrder = displayOrder;
+ if (mAdapter != null) {
+ mAdapter.setContactNameDisplayOrder(displayOrder);
+ }
+ }
+
+ public int getSortOrder() {
+ return mSortOrder;
+ }
+
+ public void setSortOrder(int sortOrder) {
+ mSortOrder = sortOrder;
+ if (mAdapter != null) {
+ mAdapter.setSortOrder(sortOrder);
+ }
+ }
+
+ public void setDirectoryResultLimit(int limit) {
+ mDirectoryResultLimit = limit;
+ }
+
+ protected boolean loadPreferences() {
+ boolean changed = false;
+ if (getContactNameDisplayOrder() != mContactsPrefs.getDisplayOrder()) {
+ setContactNameDisplayOrder(mContactsPrefs.getDisplayOrder());
+ changed = true;
+ }
+
+ if (getSortOrder() != mContactsPrefs.getSortOrder()) {
+ setSortOrder(mContactsPrefs.getSortOrder());
+ changed = true;
+ }
+
+ return changed;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ onCreateView(inflater, container);
+
+ boolean searchMode = isSearchMode();
+ mAdapter.setSearchMode(searchMode);
+ mAdapter.configureDefaultPartition(false, shouldDisplayDirectoryHeader());
+ mAdapter.setPhotoLoader(mPhotoManager);
+ mListView.setAdapter(mAdapter);
+
+ if (!isSearchMode()) {
+ mListView.setFocusableInTouchMode(true);
+ mListView.requestFocus();
+ }
+
+ if (savedInstanceState != null) {
+ mLogListEvents = savedInstanceState.getBoolean(KEY_LOGS_LIST_EVENTS, true);
+ mDataLoaded = savedInstanceState.getBoolean(KEY_DATA_LOADED, false);
+ }
+
+ return mView;
+ }
+
+ protected void onCreateView(LayoutInflater inflater, ViewGroup container) {
+ mView = inflateView(inflater, container);
+
+ mListView = (ListView)mView.findViewById(android.R.id.list);
+ if (mListView == null) {
+ throw new RuntimeException(
+ "Your content must have a ListView whose id attribute is " +
+ "'android.R.id.list'");
+ }
+
+ View emptyView = mView.findViewById(android.R.id.empty);
+ if (emptyView != null) {
+ mListView.setEmptyView(emptyView);
+ }
+
+ mListView.setOnItemClickListener(this);
+ mListView.setOnItemLongClickListener(this);
+ mListView.setOnFocusChangeListener(this);
+ mListView.setOnTouchListener(this);
+ mListView.setFastScrollEnabled(!isSearchMode());
+
+ // 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.
+ mListView.setDividerHeight(0);
+
+ // We manually save/restore the listview state
+ mListView.setSaveEnabled(false);
+
+ configureVerticalScrollbar();
+ configurePhotoLoader();
+
+ getAdapter().setFragmentRootView(getView());
+ }
+
+ protected void configurePhotoLoader() {
+ if (isPhotoLoaderEnabled() && mContext != null) {
+ if (mPhotoManager == null) {
+ mPhotoManager = ContactPhotoManager.getInstance(mContext);
+ }
+ if (mListView != null) {
+ mListView.setOnScrollListener(this);
+ }
+ if (mAdapter != null) {
+ mAdapter.setPhotoLoader(mPhotoManager);
+ }
+ }
+ }
+
+ protected void configureAdapter() {
+ if (mAdapter == null) {
+ return;
+ }
+
+ mAdapter.setQuickContactEnabled(mQuickContactEnabled);
+ mAdapter.setAdjustSelectionBoundsEnabled(mAdjustSelectionBoundsEnabled);
+ mAdapter.setIncludeFavorites(mIncludeFavorites);
+ mAdapter.setQueryString(mQueryString);
+ mAdapter.setDirectorySearchMode(mDirectorySearchMode);
+ mAdapter.setPinnedPartitionHeadersEnabled(false);
+ mAdapter.setContactNameDisplayOrder(mDisplayOrder);
+ mAdapter.setSortOrder(mSortOrder);
+ mAdapter.setSectionHeaderDisplayEnabled(mSectionHeaderDisplayEnabled);
+ mAdapter.setSelectionVisible(mSelectionVisible);
+ mAdapter.setDirectoryResultLimit(mDirectoryResultLimit);
+ mAdapter.setDarkTheme(mDarkTheme);
+ }
+
+ @Override
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+ int totalItemCount) {
+ }
+
+ @Override
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ if (scrollState == OnScrollListener.SCROLL_STATE_FLING) {
+ mPhotoManager.pause();
+ } else if (isPhotoLoaderEnabled()) {
+ mPhotoManager.resume();
+ }
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ hideSoftKeyboard();
+
+ int adjPosition = position - mListView.getHeaderViewsCount();
+ if (adjPosition >= 0) {
+ onItemClick(adjPosition, id);
+ }
+ }
+
+ @Override
+ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+ int adjPosition = position - mListView.getHeaderViewsCount();
+
+ if (adjPosition >= 0) {
+ return onItemLongClick(adjPosition, id);
+ }
+ return false;
+ }
+
+ private void hideSoftKeyboard() {
+ // Hide soft keyboard, if visible
+ InputMethodManager inputMethodManager = (InputMethodManager)
+ mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMethodManager.hideSoftInputFromWindow(mListView.getWindowToken(), 0);
+ }
+
+ /**
+ * Dismisses the soft keyboard when the list takes focus.
+ */
+ @Override
+ public void onFocusChange(View view, boolean hasFocus) {
+ if (view == mListView && hasFocus) {
+ hideSoftKeyboard();
+ }
+ }
+
+ /**
+ * Dismisses the soft keyboard when the list is touched.
+ */
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ if (view == mListView) {
+ hideSoftKeyboard();
+ }
+ return false;
+ }
+
+ @Override
+ public void onPause() {
+ // Save the scrolling state of the list view
+ mListViewTopIndex = mListView.getFirstVisiblePosition();
+ View v = mListView.getChildAt(0);
+ mListViewTopOffset = (v == null) ? 0 : (v.getTop() - mListView.getPaddingTop());
+
+ super.onPause();
+ removePendingDirectorySearchRequests();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // Restore the selection of the list view. See b/19982820.
+ // This has to be done manually because if the list view has its emptyView set,
+ // the scrolling state will be reset when clearPartitions() is called on the adapter.
+ mListView.setSelectionFromTop(mListViewTopIndex, mListViewTopOffset);
+ }
+
+ /**
+ * Restore the list state after the adapter is populated.
+ */
+ protected void completeRestoreInstanceState() {
+ if (mListState != null) {
+ mListView.onRestoreInstanceState(mListState);
+ mListState = null;
+ }
+ }
+
+ public void setDarkTheme(boolean value) {
+ mDarkTheme = value;
+ if (mAdapter != null) mAdapter.setDarkTheme(value);
+ }
+
+ /**
+ * Processes a result returned by the contact picker.
+ */
+ public void onPickerResult(Intent data) {
+ throw new UnsupportedOperationException("Picker result handler is not implemented.");
+ }
+
+ private ContactsPreferences.ChangeListener mPreferencesChangeListener =
+ new ContactsPreferences.ChangeListener() {
+ @Override
+ public void onChange() {
+ loadPreferences();
+ reloadData();
+ }
+ };
+
+ private int getDefaultVerticalScrollbarPosition() {
+ final Locale locale = Locale.getDefault();
+ final int layoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
+ switch (layoutDirection) {
+ case View.LAYOUT_DIRECTION_RTL:
+ return View.SCROLLBAR_POSITION_LEFT;
+ case View.LAYOUT_DIRECTION_LTR:
+ default:
+ return View.SCROLLBAR_POSITION_RIGHT;
+ }
+ }
+
+ public void setListType(int listType) {
+ mListType = listType;
+ }
+
+ public int getListType() {
+ return mListType;
+ }
+
+ public void setLogListEvents(boolean logListEvents) {
+ mLogListEvents = logListEvents;
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactListAdapter.java b/src/com/android/contacts/common/list/ContactListAdapter.java
new file mode 100644
index 0000000..677aa46
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactListAdapter.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.SearchSnippets;
+import android.text.TextUtils;
+import android.view.ViewGroup;
+import android.widget.ListView;
+
+import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.ContactsCompat;
+import com.android.contacts.common.preference.ContactsPreferences;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type.
+ */
+public abstract class ContactListAdapter extends MultiSelectEntryContactListAdapter {
+
+ public static class ContactQuery {
+ private static final String[] CONTACT_PROJECTION_PRIMARY = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_PRIMARY, // 1
+ Contacts.CONTACT_PRESENCE, // 2
+ Contacts.CONTACT_STATUS, // 3
+ Contacts.PHOTO_ID, // 4
+ Contacts.PHOTO_THUMBNAIL_URI, // 5
+ Contacts.LOOKUP_KEY, // 6
+ Contacts.PHONETIC_NAME, // 7
+ Contacts.STARRED, // 9
+ };
+
+ private static final String[] CONTACT_PROJECTION_ALTERNATIVE = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_ALTERNATIVE, // 1
+ Contacts.CONTACT_PRESENCE, // 2
+ Contacts.CONTACT_STATUS, // 3
+ Contacts.PHOTO_ID, // 4
+ Contacts.PHOTO_THUMBNAIL_URI, // 5
+ Contacts.LOOKUP_KEY, // 6
+ Contacts.PHONETIC_NAME, // 7
+ Contacts.STARRED, // 8
+ };
+
+ private static final String[] FILTER_PROJECTION_PRIMARY = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_PRIMARY, // 1
+ Contacts.CONTACT_PRESENCE, // 2
+ Contacts.CONTACT_STATUS, // 3
+ Contacts.PHOTO_ID, // 4
+ Contacts.PHOTO_THUMBNAIL_URI, // 5
+ Contacts.LOOKUP_KEY, // 6
+ Contacts.PHONETIC_NAME, // 7
+ Contacts.STARRED, // 8
+ SearchSnippets.SNIPPET, // 9
+ };
+
+ private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_ALTERNATIVE, // 1
+ Contacts.CONTACT_PRESENCE, // 2
+ Contacts.CONTACT_STATUS, // 3
+ Contacts.PHOTO_ID, // 4
+ Contacts.PHOTO_THUMBNAIL_URI, // 5
+ Contacts.LOOKUP_KEY, // 6
+ Contacts.PHONETIC_NAME, // 7
+ Contacts.STARRED, // 8
+ SearchSnippets.SNIPPET, // 9
+ };
+
+ public static final int CONTACT_ID = 0;
+ public static final int CONTACT_DISPLAY_NAME = 1;
+ public static final int CONTACT_PRESENCE_STATUS = 2;
+ public static final int CONTACT_CONTACT_STATUS = 3;
+ public static final int CONTACT_PHOTO_ID = 4;
+ public static final int CONTACT_PHOTO_URI = 5;
+ public static final int CONTACT_LOOKUP_KEY = 6;
+ public static final int CONTACT_PHONETIC_NAME = 7;
+ public static final int CONTACT_STARRED = 8;
+ public static final int CONTACT_SNIPPET = 9;
+ }
+
+ private CharSequence mUnknownNameText;
+
+ private long mSelectedContactDirectoryId;
+ private String mSelectedContactLookupKey;
+ private long mSelectedContactId;
+ private ContactListItemView.PhotoPosition mPhotoPosition;
+
+ public ContactListAdapter(Context context) {
+ super(context, ContactQuery.CONTACT_ID);
+
+ mUnknownNameText = context.getText(R.string.missing_name);
+ }
+
+ public void setPhotoPosition(ContactListItemView.PhotoPosition photoPosition) {
+ mPhotoPosition = photoPosition;
+ }
+
+ public ContactListItemView.PhotoPosition getPhotoPosition() {
+ return mPhotoPosition;
+ }
+
+ public CharSequence getUnknownNameText() {
+ return mUnknownNameText;
+ }
+
+ public long getSelectedContactDirectoryId() {
+ return mSelectedContactDirectoryId;
+ }
+
+ public String getSelectedContactLookupKey() {
+ return mSelectedContactLookupKey;
+ }
+
+ public long getSelectedContactId() {
+ return mSelectedContactId;
+ }
+
+ public void setSelectedContact(long selectedDirectoryId, String lookupKey, long contactId) {
+ mSelectedContactDirectoryId = selectedDirectoryId;
+ mSelectedContactLookupKey = lookupKey;
+ mSelectedContactId = contactId;
+ }
+
+ protected static Uri buildSectionIndexerUri(Uri uri) {
+ return uri.buildUpon()
+ .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true").build();
+ }
+
+ @Override
+ public String getContactDisplayName(int position) {
+ return ((Cursor) getItem(position)).getString(ContactQuery.CONTACT_DISPLAY_NAME);
+ }
+
+ /**
+ * Builds the {@link Contacts#CONTENT_LOOKUP_URI} for the given
+ * {@link ListView} position.
+ */
+ public Uri getContactUri(int position) {
+ int partitionIndex = getPartitionForPosition(position);
+ Cursor item = (Cursor)getItem(position);
+ return item != null ? getContactUri(partitionIndex, item) : null;
+ }
+
+ public Uri getContactUri(int partitionIndex, Cursor cursor) {
+ long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
+ String lookupKey = cursor.getString(ContactQuery.CONTACT_LOOKUP_KEY);
+ Uri uri = Contacts.getLookupUri(contactId, lookupKey);
+ long directoryId = ((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId();
+ if (uri != null && directoryId != Directory.DEFAULT) {
+ uri = uri.buildUpon().appendQueryParameter(
+ ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
+ }
+ return uri;
+ }
+
+ /**
+ * Returns the {@link Contacts#_ID} for the given {@link ListView} position.
+ */
+ public long getContactId(int position) {
+ final Cursor cursor = (Cursor) getItem(position);
+ return cursor == null ? -1 : cursor.getLong(ContactQuery.CONTACT_ID);
+ }
+
+ public boolean isEnterpriseContact(int position) {
+ final Cursor cursor = (Cursor) getItem(position);
+ if (cursor != null) {
+ final long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
+ return ContactsCompat.isEnterpriseContactId(contactId);
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the specified contact is selected in the list. For a
+ * contact to be shown as selected, we need both the directory and and the
+ * lookup key to be the same. We are paying no attention to the contactId,
+ * because it is volatile, especially in the case of directories.
+ */
+ public boolean isSelectedContact(int partitionIndex, Cursor cursor) {
+ long directoryId = ((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId();
+ if (getSelectedContactDirectoryId() != directoryId) {
+ return false;
+ }
+ String lookupKey = getSelectedContactLookupKey();
+ if (lookupKey != null && TextUtils.equals(lookupKey,
+ cursor.getString(ContactQuery.CONTACT_LOOKUP_KEY))) {
+ return true;
+ }
+
+ return directoryId != Directory.DEFAULT && directoryId != Directory.LOCAL_INVISIBLE
+ && getSelectedContactId() == cursor.getLong(ContactQuery.CONTACT_ID);
+ }
+
+ @Override
+ protected ContactListItemView newView(
+ Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
+ ContactListItemView view = super.newView(context, partition, cursor, position, parent);
+ view.setUnknownNameText(mUnknownNameText);
+ view.setQuickContactEnabled(isQuickContactEnabled());
+ view.setAdjustSelectionBoundsEnabled(isAdjustSelectionBoundsEnabled());
+ view.setActivatedStateSupported(isSelectionVisible());
+ if (mPhotoPosition != null) {
+ view.setPhotoPosition(mPhotoPosition);
+ }
+ return view;
+ }
+
+ protected void bindSectionHeaderAndDivider(ContactListItemView view, int position,
+ Cursor cursor) {
+ view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
+ if (isSectionHeaderDisplayEnabled()) {
+ Placement placement = getItemPlacementInSection(position);
+ view.setSectionHeader(placement.sectionHeader);
+ } else {
+ view.setSectionHeader(null);
+ }
+ }
+
+ protected void bindPhoto(final ContactListItemView view, int partitionIndex, Cursor cursor) {
+ if (!isPhotoSupported(partitionIndex)) {
+ view.removePhotoView();
+ return;
+ }
+
+ // Set the photo, if available
+ long photoId = 0;
+ if (!cursor.isNull(ContactQuery.CONTACT_PHOTO_ID)) {
+ photoId = cursor.getLong(ContactQuery.CONTACT_PHOTO_ID);
+ }
+
+ if (photoId != 0) {
+ getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false,
+ getCircularPhotos(), null);
+ } else {
+ final String photoUriString = cursor.getString(ContactQuery.CONTACT_PHOTO_URI);
+ final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
+ DefaultImageRequest request = null;
+ if (photoUri == null) {
+ request = getDefaultImageRequestFromCursor(cursor,
+ ContactQuery.CONTACT_DISPLAY_NAME,
+ ContactQuery.CONTACT_LOOKUP_KEY);
+ }
+ getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, false,
+ getCircularPhotos(), request);
+ }
+ }
+
+ protected void bindNameAndViewId(final ContactListItemView view, Cursor cursor) {
+ view.showDisplayName(
+ cursor, ContactQuery.CONTACT_DISPLAY_NAME, getContactNameDisplayOrder());
+ // Note: we don't show phonetic any more (See issue 5265330)
+
+ bindViewId(view, cursor, ContactQuery.CONTACT_ID);
+ }
+
+ protected void bindPresenceAndStatusMessage(final ContactListItemView view, Cursor cursor) {
+ view.showPresenceAndStatusMessage(cursor, ContactQuery.CONTACT_PRESENCE_STATUS,
+ ContactQuery.CONTACT_CONTACT_STATUS);
+ }
+
+ protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) {
+ view.showSnippet(cursor, ContactQuery.CONTACT_SNIPPET);
+ }
+
+ public int getSelectedContactPosition() {
+ if (mSelectedContactLookupKey == null && mSelectedContactId == 0) {
+ return -1;
+ }
+
+ Cursor cursor = null;
+ int partitionIndex = -1;
+ int partitionCount = getPartitionCount();
+ for (int i = 0; i < partitionCount; i++) {
+ DirectoryPartition partition = (DirectoryPartition) getPartition(i);
+ if (partition.getDirectoryId() == mSelectedContactDirectoryId) {
+ partitionIndex = i;
+ break;
+ }
+ }
+ if (partitionIndex == -1) {
+ return -1;
+ }
+
+ cursor = getCursor(partitionIndex);
+ if (cursor == null) {
+ return -1;
+ }
+
+ cursor.moveToPosition(-1); // Reset cursor
+ int offset = -1;
+ while (cursor.moveToNext()) {
+ if (mSelectedContactLookupKey != null) {
+ String lookupKey = cursor.getString(ContactQuery.CONTACT_LOOKUP_KEY);
+ if (mSelectedContactLookupKey.equals(lookupKey)) {
+ offset = cursor.getPosition();
+ break;
+ }
+ }
+ if (mSelectedContactId != 0 && (mSelectedContactDirectoryId == Directory.DEFAULT
+ || mSelectedContactDirectoryId == Directory.LOCAL_INVISIBLE)) {
+ long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
+ if (contactId == mSelectedContactId) {
+ offset = cursor.getPosition();
+ break;
+ }
+ }
+ }
+ if (offset == -1) {
+ return -1;
+ }
+
+ int position = getPositionForPartition(partitionIndex) + offset;
+ if (hasHeader(partitionIndex)) {
+ position++;
+ }
+ return position;
+ }
+
+ public boolean hasValidSelection() {
+ return getSelectedContactPosition() != -1;
+ }
+
+ public Uri getFirstContactUri() {
+ int partitionCount = getPartitionCount();
+ for (int i = 0; i < partitionCount; i++) {
+ DirectoryPartition partition = (DirectoryPartition) getPartition(i);
+ if (partition.isLoading()) {
+ continue;
+ }
+
+ Cursor cursor = getCursor(i);
+ if (cursor == null) {
+ continue;
+ }
+
+ if (!cursor.moveToFirst()) {
+ continue;
+ }
+
+ return getContactUri(i, cursor);
+ }
+
+ return null;
+ }
+
+ @Override
+ public void changeCursor(int partitionIndex, Cursor cursor) {
+ super.changeCursor(partitionIndex, cursor);
+
+ if (cursor == null || !cursor.moveToFirst()) {
+ return;
+ }
+
+ if (shouldIncludeFavorites()) {
+ if (cursor.getInt(ContactQuery.CONTACT_STARRED) == 1) {
+ final Set<Integer> favorites = new HashSet<>();
+ favorites.add(cursor.getInt(ContactQuery.CONTACT_ID));
+ while (cursor != null && cursor.moveToNext()) {
+ if (cursor.getInt(ContactQuery.CONTACT_STARRED) != 1
+ || favorites.contains(cursor.getInt(ContactQuery.CONTACT_ID))) {
+ break;
+ }
+ favorites.add(cursor.getInt(ContactQuery.CONTACT_ID));
+ }
+ setFavoritesSectionHeader(favorites.size());
+ }
+ }
+ }
+
+ /**
+ * @return Projection useful for children.
+ */
+ protected final String[] getProjection(boolean forSearch) {
+ final int sortOrder = getContactNameDisplayOrder();
+ if (forSearch) {
+ if (sortOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
+ return ContactQuery.FILTER_PROJECTION_PRIMARY;
+ } else {
+ return ContactQuery.FILTER_PROJECTION_ALTERNATIVE;
+ }
+ } else {
+ if (sortOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
+ return ContactQuery.CONTACT_PROJECTION_PRIMARY;
+ } else {
+ return ContactQuery.CONTACT_PROJECTION_ALTERNATIVE;
+ }
+ }
+ }
+
+ /**
+ * @return Projection from Data that is useful for children.
+ */
+ protected final String[] getDataProjectionForContacts(boolean forSearch) {
+ final int sortOrder = getContactNameDisplayOrder();
+ if (forSearch) {
+ if (sortOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
+ return replaceFirstString(ContactQuery.FILTER_PROJECTION_PRIMARY);
+ } else {
+ return replaceFirstString(ContactQuery.FILTER_PROJECTION_ALTERNATIVE);
+ }
+ } else {
+ if (sortOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
+ return replaceFirstString(ContactQuery.CONTACT_PROJECTION_PRIMARY);
+ } else {
+ return replaceFirstString(ContactQuery.CONTACT_PROJECTION_ALTERNATIVE);
+ }
+ }
+ }
+
+ /**
+ * @param sourceProjection
+ * @return Replace the first String of sourceProjection with Data.CONTACT_ID.
+ */
+ private String[] replaceFirstString(String[] sourceProjection) {
+ String[] result = sourceProjection.clone();
+ result[0] = Data.CONTACT_ID;
+ return result;
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactListFilter.java b/src/com/android/contacts/common/list/ContactListFilter.java
new file mode 100644
index 0000000..6d60a82
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactListFilter.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.SharedPreferences;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
+
+import com.android.contacts.common.logging.ListEvent;
+
+/**
+ * Contact list filter parameters.
+ */
+public final class ContactListFilter implements Comparable<ContactListFilter>, Parcelable {
+
+ public static final int FILTER_TYPE_DEFAULT = -1;
+ public static final int FILTER_TYPE_ALL_ACCOUNTS = -2;
+ public static final int FILTER_TYPE_CUSTOM = -3;
+ public static final int FILTER_TYPE_STARRED = -4;
+ public static final int FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY = -5;
+ public static final int FILTER_TYPE_SINGLE_CONTACT = -6;
+ public static final int FILTER_TYPE_GROUP_MEMBERS = -7;
+ public static final int FILTER_TYPE_DEVICE_CONTACTS = -8;
+
+ public static final int FILTER_TYPE_ACCOUNT = 0;
+
+ /**
+ * Obsolete filter which had been used in Honeycomb. This may be stored in
+ * {@link SharedPreferences}, but should be replaced with ALL filter when it is found.
+ *
+ * TODO: "group" filter and relevant variables are all obsolete. Remove them.
+ */
+ private static final int FILTER_TYPE_GROUP = 1;
+
+ private static final String KEY_FILTER_TYPE = "filter.type";
+ private static final String KEY_ACCOUNT_NAME = "filter.accountName";
+ private static final String KEY_ACCOUNT_TYPE = "filter.accountType";
+ private static final String KEY_DATA_SET = "filter.dataSet";
+
+ public final int filterType;
+ public final String accountType;
+ public final String accountName;
+ public final String dataSet;
+ public final Drawable icon;
+ private String mId;
+
+ public ContactListFilter(int filterType, String accountType, String accountName, String dataSet,
+ Drawable icon) {
+ this.filterType = filterType;
+ this.accountType = accountType;
+ this.accountName = accountName;
+ this.dataSet = dataSet;
+ this.icon = icon;
+ }
+
+ public static ContactListFilter createFilterWithType(int filterType) {
+ return new ContactListFilter(filterType, null, null, null, null);
+ }
+
+ public static ContactListFilter createAccountFilter(String accountType, String accountName,
+ String dataSet, Drawable icon) {
+ return new ContactListFilter(ContactListFilter.FILTER_TYPE_ACCOUNT, accountType,
+ accountName, dataSet, icon);
+ }
+
+ public static ContactListFilter createGroupMembersFilter(String accountType, String accountName,
+ String dataSet) {
+ return new ContactListFilter(ContactListFilter.FILTER_TYPE_GROUP_MEMBERS, accountType,
+ accountName, dataSet, /* icon */ null);
+ }
+
+ public static ContactListFilter createDeviceContactsFilter(Drawable icon) {
+ return new ContactListFilter(ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS,
+ /* accountType= */ null, /* accountName= */ null, /* dataSet= */ null, icon);
+ }
+
+ /**
+ * Whether the given {@link ContactListFilter} has a filter type that should be displayed as
+ * the default contacts list view.
+ */
+ public boolean isContactsFilterType() {
+ return filterType == ContactListFilter.FILTER_TYPE_DEFAULT
+ || filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS
+ || filterType == ContactListFilter.FILTER_TYPE_CUSTOM;
+ }
+
+ /** Returns the {@link ListEvent.ListType} for the type of this filter. */
+ public int toListType() {
+ switch (filterType) {
+ case FILTER_TYPE_DEFAULT:
+ // Fall through
+ case FILTER_TYPE_ALL_ACCOUNTS:
+ return ListEvent.ListType.ALL_CONTACTS;
+ case FILTER_TYPE_CUSTOM:
+ return ListEvent.ListType.CUSTOM;
+ case FILTER_TYPE_STARRED:
+ return ListEvent.ListType.STARRED;
+ case FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY:
+ return ListEvent.ListType.PHONE_NUMBERS;
+ case FILTER_TYPE_SINGLE_CONTACT:
+ return ListEvent.ListType.SINGLE_CONTACT;
+ case FILTER_TYPE_ACCOUNT:
+ return ListEvent.ListType.ACCOUNT;
+ case FILTER_TYPE_GROUP_MEMBERS:
+ return ListEvent.ListType.GROUP;
+ case FILTER_TYPE_DEVICE_CONTACTS:
+ return ListEvent.ListType.DEVICE;
+ }
+ return ListEvent.ListType.UNKNOWN_LIST;
+ }
+
+
+ /**
+ * Returns true if this filter is based on data and may become invalid over time.
+ */
+ public boolean isValidationRequired() {
+ return filterType == FILTER_TYPE_ACCOUNT;
+ }
+
+ @Override
+ public String toString() {
+ switch (filterType) {
+ case FILTER_TYPE_DEFAULT:
+ return "default";
+ case FILTER_TYPE_ALL_ACCOUNTS:
+ return "all_accounts";
+ case FILTER_TYPE_CUSTOM:
+ return "custom";
+ case FILTER_TYPE_STARRED:
+ return "starred";
+ case FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY:
+ return "with_phones";
+ case FILTER_TYPE_SINGLE_CONTACT:
+ return "single";
+ case FILTER_TYPE_ACCOUNT:
+ return "account: " + accountType + (dataSet != null ? "/" + dataSet : "")
+ + " " + accountName;
+ case FILTER_TYPE_GROUP_MEMBERS:
+ return "group_members";
+ case FILTER_TYPE_DEVICE_CONTACTS:
+ return "device_contacts";
+ }
+ return super.toString();
+ }
+
+ @Override
+ public int compareTo(ContactListFilter another) {
+ int res = accountName.compareTo(another.accountName);
+ if (res != 0) {
+ return res;
+ }
+
+ res = accountType.compareTo(another.accountType);
+ if (res != 0) {
+ return res;
+ }
+
+ return filterType - another.filterType;
+ }
+
+ @Override
+ public int hashCode() {
+ int code = filterType;
+ if (accountType != null) {
+ code = code * 31 + accountType.hashCode();
+ code = code * 31 + accountName.hashCode();
+ }
+ if (dataSet != null) {
+ code = code * 31 + dataSet.hashCode();
+ }
+ return code;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (!(other instanceof ContactListFilter)) {
+ return false;
+ }
+
+ ContactListFilter otherFilter = (ContactListFilter) other;
+ if (filterType != otherFilter.filterType
+ || !TextUtils.equals(accountName, otherFilter.accountName)
+ || !TextUtils.equals(accountType, otherFilter.accountType)
+ || !TextUtils.equals(dataSet, otherFilter.dataSet)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Store the given {@link ContactListFilter} to preferences. If the requested filter is
+ * of type {@link #FILTER_TYPE_SINGLE_CONTACT} then do not save it to preferences because
+ * it is a temporary state.
+ */
+ public static void storeToPreferences(SharedPreferences prefs, ContactListFilter filter) {
+ if (filter != null && filter.filterType == FILTER_TYPE_SINGLE_CONTACT) {
+ return;
+ }
+ prefs.edit()
+ .putInt(KEY_FILTER_TYPE, filter == null ? FILTER_TYPE_DEFAULT : filter.filterType)
+ .putString(KEY_ACCOUNT_NAME, filter == null ? null : filter.accountName)
+ .putString(KEY_ACCOUNT_TYPE, filter == null ? null : filter.accountType)
+ .putString(KEY_DATA_SET, filter == null ? null : filter.dataSet)
+ .apply();
+ }
+
+ /**
+ * Try to obtain ContactListFilter object saved in SharedPreference.
+ * If there's no info there, return ALL filter instead.
+ */
+ public static ContactListFilter restoreDefaultPreferences(SharedPreferences prefs) {
+ ContactListFilter filter = restoreFromPreferences(prefs);
+ if (filter == null) {
+ filter = ContactListFilter.createFilterWithType(FILTER_TYPE_ALL_ACCOUNTS);
+ }
+ // "Group" filter is obsolete and thus is not exposed anymore. The "single contact mode"
+ // should also not be stored in preferences anymore since it is a temporary state.
+ if (filter.filterType == FILTER_TYPE_GROUP ||
+ filter.filterType == FILTER_TYPE_SINGLE_CONTACT) {
+ filter = ContactListFilter.createFilterWithType(FILTER_TYPE_ALL_ACCOUNTS);
+ }
+ return filter;
+ }
+
+ private static ContactListFilter restoreFromPreferences(SharedPreferences prefs) {
+ int filterType = prefs.getInt(KEY_FILTER_TYPE, FILTER_TYPE_DEFAULT);
+ if (filterType == FILTER_TYPE_DEFAULT) {
+ return null;
+ }
+
+ String accountName = prefs.getString(KEY_ACCOUNT_NAME, null);
+ String accountType = prefs.getString(KEY_ACCOUNT_TYPE, null);
+ String dataSet = prefs.getString(KEY_DATA_SET, null);
+ return new ContactListFilter(filterType, accountType, accountName, dataSet, null);
+ }
+
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(filterType);
+ dest.writeString(accountName);
+ dest.writeString(accountType);
+ dest.writeString(dataSet);
+ }
+
+ public static final Parcelable.Creator<ContactListFilter> CREATOR =
+ new Parcelable.Creator<ContactListFilter>() {
+ @Override
+ public ContactListFilter createFromParcel(Parcel source) {
+ int filterType = source.readInt();
+ String accountName = source.readString();
+ String accountType = source.readString();
+ String dataSet = source.readString();
+ return new ContactListFilter(filterType, accountType, accountName, dataSet, null);
+ }
+
+ @Override
+ public ContactListFilter[] newArray(int size) {
+ return new ContactListFilter[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Returns a string that can be used as a stable persistent identifier for this filter.
+ */
+ public String getId() {
+ if (mId == null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(filterType);
+ if (accountType != null) {
+ sb.append('-').append(accountType);
+ }
+ if (dataSet != null) {
+ sb.append('/').append(dataSet);
+ }
+ if (accountName != null) {
+ sb.append('-').append(accountName.replace('-', '_'));
+ }
+ mId = sb.toString();
+ }
+ return mId;
+ }
+
+ /**
+ * Adds the account query parameters to the given {@code uriBuilder}.
+ *
+ * @throws IllegalStateException if the filter type is not {@link #FILTER_TYPE_ACCOUNT}.
+ */
+ public Uri.Builder addAccountQueryParameterToUrl(Uri.Builder uriBuilder) {
+ if (filterType != FILTER_TYPE_ACCOUNT
+ && filterType != FILTER_TYPE_GROUP_MEMBERS) {
+ throw new IllegalStateException(
+ "filterType must be FILTER_TYPE_ACCOUNT or FILER_TYPE_GROUP_MEMBERS");
+ }
+ uriBuilder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName);
+ uriBuilder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType);
+ if (!TextUtils.isEmpty(dataSet)) {
+ uriBuilder.appendQueryParameter(RawContacts.DATA_SET, dataSet);
+ }
+ return uriBuilder;
+ }
+
+ public String toDebugString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("[filter type: " + filterType + " (" + filterTypeToString(filterType) + ")");
+ if (filterType == FILTER_TYPE_ACCOUNT) {
+ builder.append(", accountType: " + accountType)
+ .append(", accountName: " + accountName)
+ .append(", dataSet: " + dataSet);
+ }
+ builder.append(", icon: " + icon + "]");
+ return builder.toString();
+ }
+
+ public static final String filterTypeToString(int filterType) {
+ switch (filterType) {
+ case FILTER_TYPE_DEFAULT:
+ return "FILTER_TYPE_DEFAULT";
+ case FILTER_TYPE_ALL_ACCOUNTS:
+ return "FILTER_TYPE_ALL_ACCOUNTS";
+ case FILTER_TYPE_CUSTOM:
+ return "FILTER_TYPE_CUSTOM";
+ case FILTER_TYPE_STARRED:
+ return "FILTER_TYPE_STARRED";
+ case FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY:
+ return "FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY";
+ case FILTER_TYPE_SINGLE_CONTACT:
+ return "FILTER_TYPE_SINGLE_CONTACT";
+ case FILTER_TYPE_ACCOUNT:
+ return "FILTER_TYPE_ACCOUNT";
+ case FILTER_TYPE_GROUP_MEMBERS:
+ return "FILTER_TYPE_GROUP_MEMBERS";
+ case FILTER_TYPE_DEVICE_CONTACTS:
+ return "FILTER_TYPE_DEVICE_CONTACTS";
+ default:
+ return "(unknown)";
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactListFilterController.java b/src/com/android/contacts/common/list/ContactListFilterController.java
new file mode 100644
index 0000000..48d36ed
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactListFilterController.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import com.android.contacts.common.logging.ListEvent;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages {@link ContactListFilter}. All methods must be called from UI thread.
+ */
+public abstract class ContactListFilterController {
+
+ // singleton to cache the filter controller
+ private static ContactListFilterControllerImpl sFilterController = null;
+
+ public interface ContactListFilterListener {
+ void onContactListFilterChanged();
+ }
+
+ public static ContactListFilterController getInstance(Context context) {
+ // We may need to synchronize this in the future if background task will call this.
+ if (sFilterController == null) {
+ sFilterController = new ContactListFilterControllerImpl(context);
+ }
+ return sFilterController;
+ }
+
+ public abstract void addListener(ContactListFilterListener listener);
+
+ public abstract void removeListener(ContactListFilterListener listener);
+
+ /**
+ * Return the currently-active filter.
+ */
+ public abstract ContactListFilter getFilter();
+
+ public abstract int getFilterListType();
+
+ /** Whether the persisted filter is a custom filter. */
+ public abstract boolean isCustomFilterPersisted();
+
+ /** Returns the persisted filter. */
+ public abstract ContactListFilter getPersistedFilter();
+
+ /**
+ * @param filter the filter
+ * @param persistent True when the given filter should be saved soon. False when the filter
+ * should not be saved. The latter case may happen when some Intent requires a certain type of
+ * UI (e.g. single contact) temporarily.
+ */
+ public abstract void setContactListFilter(ContactListFilter filter, boolean persistent);
+
+ public abstract void selectCustomFilter();
+
+ /**
+ * Checks if the current filter is valid and reset the filter if not. It may happen when
+ * an account is removed while the filter points to the account with
+ * {@link ContactListFilter#FILTER_TYPE_ACCOUNT} type, for example. It may also happen if
+ * the current filter is {@link ContactListFilter#FILTER_TYPE_SINGLE_CONTACT}, in
+ * which case, we should switch to the last saved filter in {@link SharedPreferences}.
+ */
+ public abstract void checkFilterValidity(boolean notifyListeners);
+}
+
+/**
+ * Stores the {@link ContactListFilter} selected by the user and saves it to
+ * {@link SharedPreferences} if necessary.
+ */
+class ContactListFilterControllerImpl extends ContactListFilterController {
+ private final Context mContext;
+ private final List<ContactListFilterListener> mListeners =
+ new ArrayList<ContactListFilterListener>();
+ private ContactListFilter mFilter;
+
+ public ContactListFilterControllerImpl(Context context) {
+ mContext = context.getApplicationContext();
+ mFilter = ContactListFilter.restoreDefaultPreferences(getSharedPreferences());
+ checkFilterValidity(true /* notify listeners */);
+ }
+
+ @Override
+ public void addListener(ContactListFilterListener listener) {
+ mListeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(ContactListFilterListener listener) {
+ mListeners.remove(listener);
+ }
+
+ @Override
+ public ContactListFilter getFilter() {
+ return mFilter;
+ }
+
+ @Override
+ public int getFilterListType() {
+ return mFilter == null ? ListEvent.ListType.UNKNOWN_LIST : mFilter.toListType();
+ }
+
+ @Override
+ public boolean isCustomFilterPersisted() {
+ final ContactListFilter filter = getPersistedFilter();
+ return filter != null && filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM;
+ }
+
+ @Override
+ public ContactListFilter getPersistedFilter() {
+ return ContactListFilter.restoreDefaultPreferences(getSharedPreferences());
+ }
+
+ private SharedPreferences getSharedPreferences() {
+ return PreferenceManager.getDefaultSharedPreferences(mContext);
+ }
+
+ @Override
+ public void setContactListFilter(ContactListFilter filter, boolean persistent) {
+ setContactListFilter(filter, persistent, /* notifyListeners */ true);
+ }
+
+ private void setContactListFilter(ContactListFilter filter, boolean persistent,
+ boolean notifyListeners) {
+ if (!filter.equals(mFilter)) {
+ mFilter = filter;
+ if (persistent) {
+ ContactListFilter.storeToPreferences(getSharedPreferences(), mFilter);
+ }
+ if (notifyListeners && !mListeners.isEmpty()) {
+ notifyContactListFilterChanged();
+ }
+ }
+ }
+
+ @Override
+ public void selectCustomFilter() {
+ setContactListFilter(ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_CUSTOM), /* persistent */ true);
+ }
+
+ private void notifyContactListFilterChanged() {
+ for (ContactListFilterListener listener : mListeners) {
+ listener.onContactListFilterChanged();
+ }
+ }
+
+ @Override
+ public void checkFilterValidity(boolean notifyListeners) {
+ if (mFilter == null) {
+ return;
+ }
+
+ switch (mFilter.filterType) {
+ case ContactListFilter.FILTER_TYPE_SINGLE_CONTACT:
+ setContactListFilter(
+ ContactListFilter.restoreDefaultPreferences(getSharedPreferences()),
+ false, notifyListeners);
+ break;
+ case ContactListFilter.FILTER_TYPE_ACCOUNT:
+ if (!filterAccountExists()) {
+ // The current account filter points to invalid account. Use "all" filter
+ // instead.
+ setContactListFilter(ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS), true, notifyListeners);
+ }
+ break;
+ case ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS:
+ if (!localAccountExists()) {
+ setContactListFilter(ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS), true, notifyListeners);
+ }
+ break;
+ }
+ }
+
+ /**
+ * @return true if the Account for the current filter exists.
+ */
+ private boolean filterAccountExists() {
+ final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(mContext);
+ final AccountWithDataSet filterAccount = new AccountWithDataSet(
+ mFilter.accountName, mFilter.accountType, mFilter.dataSet);
+ return accountTypeManager.contains(filterAccount, /* contactWritableOnly */ false);
+ }
+
+ /**
+ * @return true if the local account still exists.
+ */
+ private boolean localAccountExists() {
+ final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(mContext);
+ final AccountWithDataSet localAccount = AccountWithDataSet.getLocalAccount();
+ return accountTypeManager.contains(localAccount, /* contactWritableOnly */ false);
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactListFilterView.java b/src/com/android/contacts/common/list/ContactListFilterView.java
new file mode 100644
index 0000000..76e43aa
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactListFilterView.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2012 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.common.list;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.TextView;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountType;
+
+/**
+ * Contact list filter parameters.
+ */
+public class ContactListFilterView extends LinearLayout {
+
+ private static final String TAG = ContactListFilterView.class.getSimpleName();
+
+ private ImageView mIcon;
+ private TextView mAccountType;
+ private TextView mAccountUserName;
+ private RadioButton mRadioButton;
+ private ContactListFilter mFilter;
+ private boolean mSingleAccount;
+
+ public ContactListFilterView(Context context) {
+ super(context);
+ }
+
+ public ContactListFilterView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setContactListFilter(ContactListFilter filter) {
+ mFilter = filter;
+ }
+
+ public ContactListFilter getContactListFilter() {
+ return mFilter;
+ }
+
+ public void setSingleAccount(boolean flag) {
+ this.mSingleAccount = flag;
+ }
+
+ @Override
+ public void setActivated(boolean activated) {
+ super.setActivated(activated);
+ if (mRadioButton != null) {
+ mRadioButton.setChecked(activated);
+ } else {
+ // We're guarding against null-pointer exceptions,
+ // but otherwise this code is not expected to work
+ // properly if the button hasn't been initialized.
+ Log.wtf(TAG, "radio-button cannot be activated because it is null");
+ }
+ setContentDescription(generateContentDescription());
+ }
+
+ public boolean isChecked() {
+ return mRadioButton.isChecked();
+ }
+
+ public void bindView(AccountTypeManager accountTypes) {
+ if (mAccountType == null) {
+ mIcon = (ImageView) findViewById(R.id.icon);
+ mAccountType = (TextView) findViewById(R.id.accountType);
+ mAccountUserName = (TextView) findViewById(R.id.accountUserName);
+ mRadioButton = (RadioButton) findViewById(R.id.radioButton);
+ mRadioButton.setChecked(isActivated());
+ }
+
+ if (mFilter == null) {
+ mAccountType.setText(R.string.contactsList);
+ return;
+ }
+
+ mAccountUserName.setVisibility(View.GONE);
+ switch (mFilter.filterType) {
+ case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS: {
+ bindView(0, R.string.list_filter_all_accounts);
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_STARRED: {
+ bindView(R.drawable.ic_menu_star_holo_light, R.string.list_filter_all_starred);
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_CUSTOM: {
+ bindView(0, R.string.list_filter_customize);
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY: {
+ bindView(0, R.string.list_filter_phones);
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_SINGLE_CONTACT: {
+ bindView(0, R.string.list_filter_single);
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_ACCOUNT: {
+ mAccountUserName.setVisibility(View.VISIBLE);
+ mIcon.setVisibility(View.VISIBLE);
+ if (mFilter.icon != null) {
+ mIcon.setImageDrawable(mFilter.icon);
+ } else {
+ mIcon.setImageResource(R.drawable.unknown_source);
+ }
+ final AccountType accountType =
+ accountTypes.getAccountType(mFilter.accountType, mFilter.dataSet);
+ mAccountUserName.setText(mFilter.accountName);
+ mAccountType.setText(accountType.getDisplayLabel(getContext()));
+ break;
+ }
+ }
+ setContentDescription(generateContentDescription());
+ }
+
+ private void bindView(int iconResource, int textResource) {
+ if (iconResource != 0) {
+ mIcon.setVisibility(View.VISIBLE);
+ mIcon.setImageResource(iconResource);
+ } else {
+ mIcon.setVisibility(View.GONE);
+ }
+
+ mAccountType.setText(textResource);
+ }
+
+ String generateContentDescription() {
+ final StringBuilder sb = new StringBuilder();
+ if (!TextUtils.isEmpty(mAccountType.getText())) {
+ sb.append(mAccountType.getText());
+ }
+ if (!TextUtils.isEmpty(mAccountUserName.getText())) {
+ if (sb.length() > 0) {
+ sb.append(" ");
+ }
+ sb.append(mAccountUserName.getText());
+ }
+ return getContext().getString(isActivated() ? R.string.account_filter_view_checked :
+ R.string.account_filter_view_not_checked, sb.toString());
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactListItemView.java b/src/com/android/contacts/common/list/ContactListItemView.java
new file mode 100644
index 0000000..1dc99ef
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactListItemView.java
@@ -0,0 +1,1892 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.database.CharArrayBuffer;
+import android.database.Cursor;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.SearchSnippets;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v7.widget.AppCompatCheckBox;
+import android.support.v7.widget.AppCompatImageButton;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.TextUtils.TruncateAt;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView.SelectionBoundsAdjuster;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.QuickContactBadge;
+import android.widget.TextView;
+
+import com.android.contacts.common.ContactPresenceIconUtil;
+import com.android.contacts.common.ContactStatusUtil;
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
+import com.android.contacts.common.format.TextHighlighter;
+import com.android.contacts.common.util.ContactDisplayUtils;
+import com.android.contacts.common.util.SearchUtil;
+import com.android.contacts.common.util.ViewUtil;
+
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A custom view for an item in the contact list.
+ * The view contains the contact's photo, a set of text views (for name, status, etc...) and
+ * icons for presence and call.
+ * The view uses no XML file for layout and all the measurements and layouts are done
+ * in the onMeasure and onLayout methods.
+ *
+ * The layout puts the contact's photo on the right side of the view, the call icon (if present)
+ * to the left of the photo, the text lines are aligned to the left and the presence icon (if
+ * present) is set to the left of the status line.
+ *
+ * The layout also supports a header (used as a header of a group of contacts) that is above the
+ * contact's data and a divider between contact view.
+ */
+
+public class ContactListItemView extends ViewGroup
+ implements SelectionBoundsAdjuster {
+
+ private static final String TAG = "ContactListItemView";
+
+ // Style values for layout and appearance
+ // The initialized values are defaults if none is provided through xml.
+ private int mPreferredHeight = 0;
+ private int mGapBetweenImageAndText = 0;
+ private int mGapBetweenIndexerAndImage = 0;
+ private int mGapBetweenLabelAndData = 0;
+ private int mPresenceIconMargin = 4;
+ private int mPresenceIconSize = 16;
+ private int mTextIndent = 0;
+ private int mTextOffsetTop;
+ private int mAvatarOffsetTop;
+ private int mNameTextViewTextSize;
+ private int mHeaderWidth;
+ private Drawable mActivatedBackgroundDrawable;
+ private int mVideoCallIconSize = 32;
+ private int mVideoCallIconMargin = 16;
+ private int mGapFromScrollBar = 20;
+
+ // Set in onLayout. Represent left and right position of the View on the screen.
+ private int mLeftOffset;
+ private int mRightOffset;
+
+ /**
+ * Used with {@link #mLabelView}, specifying the width ratio between label and data.
+ */
+ private int mLabelViewWidthWeight = 3;
+ /**
+ * Used with {@link #mDataView}, specifying the width ratio between label and data.
+ */
+ private int mDataViewWidthWeight = 5;
+
+ protected static class HighlightSequence {
+ private final int start;
+ private final int end;
+
+ HighlightSequence(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+ }
+
+ private ArrayList<HighlightSequence> mNameHighlightSequence;
+ private ArrayList<HighlightSequence> mNumberHighlightSequence;
+
+ // Highlighting prefix for names.
+ private String mHighlightedPrefix;
+
+ /**
+ * Used to notify listeners when a video call icon is clicked.
+ */
+ private PhoneNumberListAdapter.Listener mPhoneNumberListAdapterListener;
+
+ /**
+ * Indicates whether to show the "video call" icon, used to initiate a video call.
+ */
+ private boolean mShowVideoCallIcon = false;
+
+ /**
+ * Indicates whether the view should leave room for the "video call" icon.
+ */
+ private boolean mSupportVideoCallIcon = false;
+
+ /**
+ * Where to put contact photo. This affects the other Views' layout or look-and-feel.
+ *
+ * TODO: replace enum with int constants
+ */
+ public enum PhotoPosition {
+ LEFT,
+ RIGHT
+ }
+
+ static public final PhotoPosition getDefaultPhotoPosition(boolean opposite) {
+ final Locale locale = Locale.getDefault();
+ final int layoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
+ switch (layoutDirection) {
+ case View.LAYOUT_DIRECTION_RTL:
+ return (opposite ? PhotoPosition.LEFT : PhotoPosition.RIGHT);
+ case View.LAYOUT_DIRECTION_LTR:
+ default:
+ return (opposite ? PhotoPosition.RIGHT : PhotoPosition.LEFT);
+ }
+ }
+
+ private PhotoPosition mPhotoPosition = getDefaultPhotoPosition(false /* normal/non opposite */);
+
+ // Header layout data
+ private View mHeaderView;
+ private boolean mIsSectionHeaderEnabled;
+
+ // The views inside the contact view
+ private boolean mQuickContactEnabled = true;
+ private QuickContactBadge mQuickContact;
+ private ImageView mPhotoView;
+ private TextView mNameTextView;
+ private TextView mPhoneticNameTextView;
+ private TextView mLabelView;
+ private TextView mDataView;
+ private TextView mSnippetView;
+ private TextView mStatusView;
+ private ImageView mPresenceIcon;
+ private AppCompatCheckBox mCheckBox;
+ private AppCompatImageButton mDeleteImageButton;
+ private ImageView mVideoCallIcon;
+ private ImageView mWorkProfileIcon;
+
+ private ColorStateList mSecondaryTextColor;
+
+ private int mDefaultPhotoViewSize = 0;
+ /**
+ * Can be effective even when {@link #mPhotoView} is null, as we want to have horizontal padding
+ * to align other data in this View.
+ */
+ private int mPhotoViewWidth;
+ /**
+ * Can be effective even when {@link #mPhotoView} is null, as we want to have vertical padding.
+ */
+ private int mPhotoViewHeight;
+
+ /**
+ * Only effective when {@link #mPhotoView} is null.
+ * When true all the Views on the right side of the photo should have horizontal padding on
+ * those left assuming there is a photo.
+ */
+ private boolean mKeepHorizontalPaddingForPhotoView;
+ /**
+ * Only effective when {@link #mPhotoView} is null.
+ */
+ private boolean mKeepVerticalPaddingForPhotoView;
+
+ /**
+ * True when {@link #mPhotoViewWidth} and {@link #mPhotoViewHeight} are ready for being used.
+ * False indicates those values should be updated before being used in position calculation.
+ */
+ private boolean mPhotoViewWidthAndHeightAreReady = false;
+
+ private int mNameTextViewHeight;
+ private int mNameTextViewTextColor = Color.BLACK;
+ private int mPhoneticNameTextViewHeight;
+ private int mLabelViewHeight;
+ private int mDataViewHeight;
+ private int mSnippetTextViewHeight;
+ private int mStatusTextViewHeight;
+ private int mCheckBoxHeight;
+ private int mCheckBoxWidth;
+ private int mDeleteImageButtonHeight;
+ private int mDeleteImageButtonWidth;
+
+ // Holds Math.max(mLabelTextViewHeight, mDataViewHeight), assuming Label and Data share the
+ // same row.
+ private int mLabelAndDataViewMaxHeight;
+
+ // TODO: some TextView fields are using CharArrayBuffer while some are not. Determine which is
+ // more efficient for each case or in general, and simplify the whole implementation.
+ // Note: if we're sure MARQUEE will be used every time, there's no reason to use
+ // CharArrayBuffer, since MARQUEE requires Span and thus we need to copy characters inside the
+ // buffer to Spannable once, while CharArrayBuffer is for directly applying char array to
+ // TextView without any modification.
+ private final CharArrayBuffer mDataBuffer = new CharArrayBuffer(128);
+ private final CharArrayBuffer mPhoneticNameBuffer = new CharArrayBuffer(128);
+
+ private boolean mActivatedStateSupported;
+ private boolean mAdjustSelectionBoundsEnabled = true;
+
+ private Rect mBoundsWithoutHeader = new Rect();
+
+ /** A helper used to highlight a prefix in a text field. */
+ private final TextHighlighter mTextHighlighter;
+ private CharSequence mUnknownNameText;
+ private int mPosition;
+
+ public ContactListItemView(Context context) {
+ super(context);
+
+ mTextHighlighter = new TextHighlighter(Typeface.BOLD);
+ mNameHighlightSequence = new ArrayList<HighlightSequence>();
+ mNumberHighlightSequence = new ArrayList<HighlightSequence>();
+ }
+
+ public ContactListItemView(Context context, AttributeSet attrs, boolean supportVideoCallIcon) {
+ this(context, attrs);
+
+ mSupportVideoCallIcon = supportVideoCallIcon;
+ }
+
+ public ContactListItemView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ TypedArray a;
+
+ if (R.styleable.ContactListItemView != null) {
+ // Read all style values
+ a = getContext().obtainStyledAttributes(attrs, R.styleable.ContactListItemView);
+ mPreferredHeight = a.getDimensionPixelSize(
+ R.styleable.ContactListItemView_list_item_height, mPreferredHeight);
+ mActivatedBackgroundDrawable = a.getDrawable(
+ R.styleable.ContactListItemView_activated_background);
+
+ mGapBetweenImageAndText = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_gap_between_image_and_text,
+ mGapBetweenImageAndText);
+ mGapBetweenIndexerAndImage = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_gap_between_indexer_and_image,
+ mGapBetweenIndexerAndImage);
+ mGapBetweenLabelAndData = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_gap_between_label_and_data,
+ mGapBetweenLabelAndData);
+ mPresenceIconMargin = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_presence_icon_margin,
+ mPresenceIconMargin);
+ mPresenceIconSize = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_presence_icon_size,
+ mPresenceIconSize);
+ mDefaultPhotoViewSize = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_photo_size, mDefaultPhotoViewSize);
+ mTextIndent = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_text_indent, mTextIndent);
+ mTextOffsetTop = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_text_offset_top, mTextOffsetTop);
+ mAvatarOffsetTop = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_avatar_offset_top, mAvatarOffsetTop);
+ mDataViewWidthWeight = a.getInteger(
+ R.styleable.ContactListItemView_list_item_data_width_weight,
+ mDataViewWidthWeight);
+ mLabelViewWidthWeight = a.getInteger(
+ R.styleable.ContactListItemView_list_item_label_width_weight,
+ mLabelViewWidthWeight);
+ mNameTextViewTextColor = a.getColor(
+ R.styleable.ContactListItemView_list_item_name_text_color,
+ mNameTextViewTextColor);
+ mNameTextViewTextSize = (int) a.getDimension(
+ R.styleable.ContactListItemView_list_item_name_text_size,
+ (int) getResources().getDimension(R.dimen.contact_browser_list_item_text_size));
+ mVideoCallIconSize = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_video_call_icon_size,
+ mVideoCallIconSize);
+ mVideoCallIconMargin = a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_video_call_icon_margin,
+ mVideoCallIconMargin);
+
+
+ setPaddingRelative(
+ a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_padding_left, 0),
+ a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_padding_top, 0),
+ a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_padding_right, 0),
+ a.getDimensionPixelOffset(
+ R.styleable.ContactListItemView_list_item_padding_bottom, 0));
+
+ a.recycle();
+ }
+
+ mTextHighlighter = new TextHighlighter(Typeface.BOLD);
+
+ if (R.styleable.Theme != null) {
+ a = getContext().obtainStyledAttributes(R.styleable.Theme);
+ mSecondaryTextColor = a.getColorStateList(R.styleable.Theme_android_textColorSecondary);
+ a.recycle();
+ }
+
+ mHeaderWidth =
+ getResources().getDimensionPixelSize(R.dimen.contact_list_section_header_width);
+
+ if (mActivatedBackgroundDrawable != null) {
+ mActivatedBackgroundDrawable.setCallback(this);
+ }
+
+ mNameHighlightSequence = new ArrayList<HighlightSequence>();
+ mNumberHighlightSequence = new ArrayList<HighlightSequence>();
+
+ setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
+ }
+
+ public void setUnknownNameText(CharSequence unknownNameText) {
+ mUnknownNameText = unknownNameText;
+ }
+
+ public void setQuickContactEnabled(boolean flag) {
+ mQuickContactEnabled = flag;
+ }
+
+ /**
+ * Sets whether the video calling icon is shown. For the video calling icon to be shown,
+ * {@link #mSupportVideoCallIcon} must be {@code true}.
+ *
+ * @param showVideoCallIcon {@code true} if the video calling icon is shown, {@code false}
+ * otherwise.
+ * @param listener Listener to notify when the video calling icon is clicked.
+ * @param position The position in the adapater of the video calling icon.
+ */
+ public void setShowVideoCallIcon(boolean showVideoCallIcon,
+ PhoneNumberListAdapter.Listener listener, int position) {
+ mShowVideoCallIcon = showVideoCallIcon;
+ mPhoneNumberListAdapterListener = listener;
+ mPosition = position;
+
+ if (mShowVideoCallIcon) {
+ if (mVideoCallIcon == null) {
+ mVideoCallIcon = new ImageView(getContext());
+ addView(mVideoCallIcon);
+ }
+ mVideoCallIcon.setContentDescription(getContext().getString(
+ R.string.description_search_video_call));
+ mVideoCallIcon.setImageResource(R.drawable.ic_search_video_call);
+ mVideoCallIcon.setScaleType(ScaleType.CENTER);
+ mVideoCallIcon.setVisibility(View.VISIBLE);
+ mVideoCallIcon.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Inform the adapter that the video calling icon was clicked.
+ if (mPhoneNumberListAdapterListener != null) {
+ mPhoneNumberListAdapterListener.onVideoCallIconClicked(mPosition);
+ }
+ }
+ });
+ } else {
+ if (mVideoCallIcon != null) {
+ mVideoCallIcon.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ /**
+ * Sets whether the view supports a video calling icon. This is independent of whether the view
+ * is actually showing an icon. Support for the video calling icon ensures that the layout
+ * leaves space for the video icon, should it be shown.
+ *
+ * @param supportVideoCallIcon {@code true} if the video call icon is supported, {@code false}
+ * otherwise.
+ */
+ public void setSupportVideoCallIcon(boolean supportVideoCallIcon) {
+ mSupportVideoCallIcon = supportVideoCallIcon;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // We will match parent's width and wrap content vertically, but make sure
+ // height is no less than listPreferredItemHeight.
+ final int specWidth = resolveSize(0, widthMeasureSpec);
+ final int preferredHeight = mPreferredHeight;
+
+ mNameTextViewHeight = 0;
+ mPhoneticNameTextViewHeight = 0;
+ mLabelViewHeight = 0;
+ mDataViewHeight = 0;
+ mLabelAndDataViewMaxHeight = 0;
+ mSnippetTextViewHeight = 0;
+ mStatusTextViewHeight = 0;
+ mCheckBoxWidth = 0;
+ mCheckBoxHeight = 0;
+ mDeleteImageButtonWidth = 0;
+ mDeleteImageButtonHeight = 0;
+
+ ensurePhotoViewSize();
+
+ // Width each TextView is able to use.
+ int effectiveWidth;
+ // All the other Views will honor the photo, so available width for them may be shrunk.
+ if (mPhotoViewWidth > 0 || mKeepHorizontalPaddingForPhotoView) {
+ effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight()
+ - (mPhotoViewWidth + mGapBetweenImageAndText);
+ } else {
+ effectiveWidth = specWidth - getPaddingLeft() - getPaddingRight();
+ }
+
+ if (mIsSectionHeaderEnabled) {
+ effectiveWidth -= mHeaderWidth + mGapBetweenIndexerAndImage;
+ }
+
+ if (mSupportVideoCallIcon) {
+ effectiveWidth -= (mVideoCallIconSize + mVideoCallIconMargin);
+ }
+
+ // Go over all visible text views and measure actual width of each of them.
+ // Also calculate their heights to get the total height for this entire view.
+
+ if (isVisible(mCheckBox)) {
+ mCheckBox.measure(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mCheckBoxWidth = mCheckBox.getMeasuredWidth();
+ mCheckBoxHeight = mCheckBox.getMeasuredHeight();
+ effectiveWidth -= mCheckBoxWidth + mGapBetweenImageAndText;
+ }
+
+ if (isVisible(mDeleteImageButton)) {
+ mDeleteImageButton.measure(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mDeleteImageButtonWidth = mDeleteImageButton.getMeasuredWidth();
+ mDeleteImageButtonHeight = mDeleteImageButton.getMeasuredHeight();
+ effectiveWidth -= mDeleteImageButtonWidth + mGapBetweenImageAndText;
+ }
+
+ if (isVisible(mNameTextView)) {
+ // Calculate width for name text - this parallels similar measurement in onLayout.
+ int nameTextWidth = effectiveWidth;
+ if (mPhotoPosition != PhotoPosition.LEFT) {
+ nameTextWidth -= mTextIndent;
+ }
+ mNameTextView.measure(
+ MeasureSpec.makeMeasureSpec(nameTextWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mNameTextViewHeight = mNameTextView.getMeasuredHeight();
+ }
+
+ if (isVisible(mPhoneticNameTextView)) {
+ mPhoneticNameTextView.measure(
+ MeasureSpec.makeMeasureSpec(effectiveWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mPhoneticNameTextViewHeight = mPhoneticNameTextView.getMeasuredHeight();
+ }
+
+ // If both data (phone number/email address) and label (type like "MOBILE") are quite long,
+ // we should ellipsize both using appropriate ratio.
+ final int dataWidth;
+ final int labelWidth;
+ if (isVisible(mDataView)) {
+ if (isVisible(mLabelView)) {
+ final int totalWidth = effectiveWidth - mGapBetweenLabelAndData;
+ dataWidth = ((totalWidth * mDataViewWidthWeight)
+ / (mDataViewWidthWeight + mLabelViewWidthWeight));
+ labelWidth = ((totalWidth * mLabelViewWidthWeight) /
+ (mDataViewWidthWeight + mLabelViewWidthWeight));
+ } else {
+ dataWidth = effectiveWidth;
+ labelWidth = 0;
+ }
+ } else {
+ dataWidth = 0;
+ if (isVisible(mLabelView)) {
+ labelWidth = effectiveWidth;
+ } else {
+ labelWidth = 0;
+ }
+ }
+
+ if (isVisible(mDataView)) {
+ mDataView.measure(MeasureSpec.makeMeasureSpec(dataWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mDataViewHeight = mDataView.getMeasuredHeight();
+ }
+
+ if (isVisible(mLabelView)) {
+ mLabelView.measure(MeasureSpec.makeMeasureSpec(labelWidth, MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mLabelViewHeight = mLabelView.getMeasuredHeight();
+ }
+ mLabelAndDataViewMaxHeight = Math.max(mLabelViewHeight, mDataViewHeight);
+
+ if (isVisible(mSnippetView)) {
+ mSnippetView.measure(
+ MeasureSpec.makeMeasureSpec(effectiveWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mSnippetTextViewHeight = mSnippetView.getMeasuredHeight();
+ }
+
+ // Status view height is the biggest of the text view and the presence icon
+ if (isVisible(mPresenceIcon)) {
+ mPresenceIcon.measure(
+ MeasureSpec.makeMeasureSpec(mPresenceIconSize, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(mPresenceIconSize, MeasureSpec.EXACTLY));
+ mStatusTextViewHeight = mPresenceIcon.getMeasuredHeight();
+ }
+
+ if (mSupportVideoCallIcon && isVisible(mVideoCallIcon)) {
+ mVideoCallIcon.measure(
+ MeasureSpec.makeMeasureSpec(mVideoCallIconSize, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(mVideoCallIconSize, MeasureSpec.EXACTLY));
+ }
+
+ if (isVisible(mWorkProfileIcon)) {
+ mWorkProfileIcon.measure(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mNameTextViewHeight =
+ Math.max(mNameTextViewHeight, mWorkProfileIcon.getMeasuredHeight());
+ }
+
+ if (isVisible(mStatusView)) {
+ // Presence and status are in a same row, so status will be affected by icon size.
+ final int statusWidth;
+ if (isVisible(mPresenceIcon)) {
+ statusWidth = (effectiveWidth - mPresenceIcon.getMeasuredWidth()
+ - mPresenceIconMargin);
+ } else {
+ statusWidth = effectiveWidth;
+ }
+ mStatusView.measure(MeasureSpec.makeMeasureSpec(statusWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mStatusTextViewHeight =
+ Math.max(mStatusTextViewHeight, mStatusView.getMeasuredHeight());
+ }
+
+ // Calculate height including padding.
+ int height = (mNameTextViewHeight + mPhoneticNameTextViewHeight +
+ mLabelAndDataViewMaxHeight +
+ mSnippetTextViewHeight + mStatusTextViewHeight);
+
+ // Make sure the height is at least as high as the photo
+ height = Math.max(height, mPhotoViewHeight + getPaddingBottom() + getPaddingTop());
+
+ // Make sure height is at least the preferred height
+ height = Math.max(height, preferredHeight);
+
+ // Measure the header if it is visible.
+ if (mHeaderView != null && mHeaderView.getVisibility() == VISIBLE) {
+ mHeaderView.measure(
+ MeasureSpec.makeMeasureSpec(mHeaderWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ }
+
+ setMeasuredDimension(specWidth, height);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ final int height = bottom - top;
+ final int width = right - left;
+
+ // Determine the vertical bounds by laying out the header first.
+ int topBound = 0;
+ int bottomBound = height;
+ int leftBound = getPaddingLeft();
+ int rightBound = width - getPaddingRight();
+
+ final boolean isLayoutRtl = ViewUtil.isViewLayoutRtl(this);
+
+ // Put the section header on the left side of the contact view.
+ if (mIsSectionHeaderEnabled) {
+ if (mHeaderView != null) {
+ int headerHeight = mHeaderView.getMeasuredHeight();
+ int headerTopBound = (bottomBound + topBound - headerHeight) / 2 + mTextOffsetTop;
+
+ mHeaderView.layout(
+ isLayoutRtl ? rightBound - mHeaderWidth : leftBound,
+ headerTopBound,
+ isLayoutRtl ? rightBound : leftBound + mHeaderWidth,
+ headerTopBound + headerHeight);
+ }
+ if (isLayoutRtl) {
+ rightBound -= mHeaderWidth;
+ } else {
+ leftBound += mHeaderWidth;
+ }
+ }
+
+ mBoundsWithoutHeader.set(left + leftBound, topBound, left + rightBound, bottomBound);
+ mLeftOffset = left + leftBound;
+ mRightOffset = left + rightBound;
+ if (isLayoutRtl) {
+ rightBound -= mGapBetweenIndexerAndImage;
+ } else {
+ leftBound += mGapBetweenIndexerAndImage;
+ }
+
+ if (mActivatedStateSupported && isActivated()) {
+ mActivatedBackgroundDrawable.setBounds(mBoundsWithoutHeader);
+ }
+
+ if (isVisible(mCheckBox)) {
+ final int photoTop = topBound + (bottomBound - topBound - mCheckBoxHeight) / 2;
+ if (mPhotoPosition == PhotoPosition.LEFT) {
+ mCheckBox.layout(rightBound - mGapFromScrollBar - mCheckBoxWidth,
+ photoTop,
+ rightBound - mGapFromScrollBar,
+ photoTop + mCheckBoxHeight);
+ } else {
+ mCheckBox.layout(leftBound + mGapFromScrollBar,
+ photoTop,
+ leftBound + mGapFromScrollBar + mCheckBoxWidth,
+ photoTop + mCheckBoxHeight);
+ }
+ }
+
+ if (isVisible(mDeleteImageButton)) {
+ final int photoTop = topBound + (bottomBound - topBound - mDeleteImageButtonHeight) / 2;
+ final int mDeleteImageButtonSize = mDeleteImageButtonHeight > mDeleteImageButtonWidth
+ ? mDeleteImageButtonHeight : mDeleteImageButtonWidth;
+ if (mPhotoPosition == PhotoPosition.LEFT) {
+ mDeleteImageButton.layout(rightBound - mDeleteImageButtonSize,
+ photoTop,
+ rightBound,
+ photoTop + mDeleteImageButtonSize);
+ rightBound -= mDeleteImageButtonSize;
+ } else {
+ mDeleteImageButton.layout(leftBound,
+ photoTop,
+ leftBound + mDeleteImageButtonSize,
+ photoTop + mDeleteImageButtonSize);
+ leftBound += mDeleteImageButtonSize;
+ }
+ }
+
+ final View photoView = mQuickContact != null ? mQuickContact : mPhotoView;
+ if (mPhotoPosition == PhotoPosition.LEFT) {
+ // Photo is the left most view. All the other Views should on the right of the photo.
+ if (photoView != null) {
+ // Center the photo vertically
+ final int photoTop = topBound + (bottomBound - topBound - mPhotoViewHeight) / 2
+ + mAvatarOffsetTop;
+ photoView.layout(
+ leftBound,
+ photoTop,
+ leftBound + mPhotoViewWidth,
+ photoTop + mPhotoViewHeight);
+ leftBound += mPhotoViewWidth + mGapBetweenImageAndText;
+ } else if (mKeepHorizontalPaddingForPhotoView) {
+ // Draw nothing but keep the padding.
+ leftBound += mPhotoViewWidth + mGapBetweenImageAndText;
+ }
+ } else {
+ // Photo is the right most view. Right bound should be adjusted that way.
+ if (photoView != null) {
+ // Center the photo vertically
+ final int photoTop = topBound + (bottomBound - topBound - mPhotoViewHeight) / 2
+ + mAvatarOffsetTop;
+ photoView.layout(
+ rightBound - mPhotoViewWidth,
+ photoTop,
+ rightBound,
+ photoTop + mPhotoViewHeight);
+ rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
+ } else if (mKeepHorizontalPaddingForPhotoView) {
+ // Draw nothing but keep the padding.
+ rightBound -= (mPhotoViewWidth + mGapBetweenImageAndText);
+ }
+
+ // Add indent between left-most padding and texts.
+ leftBound += mTextIndent;
+ }
+
+ if (mSupportVideoCallIcon) {
+ // Place the video call button at the end of the list (e.g. take into account RTL mode).
+ if (isVisible(mVideoCallIcon)) {
+ // Center the video icon vertically
+ final int videoIconTop = topBound +
+ (bottomBound - topBound - mVideoCallIconSize) / 2;
+
+ if (!isLayoutRtl) {
+ // When photo is on left, video icon is placed on the right edge.
+ mVideoCallIcon.layout(rightBound - mVideoCallIconSize,
+ videoIconTop,
+ rightBound,
+ videoIconTop + mVideoCallIconSize);
+ } else {
+ // When photo is on right, video icon is placed on the left edge.
+ mVideoCallIcon.layout(leftBound,
+ videoIconTop,
+ leftBound + mVideoCallIconSize,
+ videoIconTop + mVideoCallIconSize);
+ }
+ }
+
+ if (mPhotoPosition == PhotoPosition.LEFT) {
+ rightBound -= (mVideoCallIconSize + mVideoCallIconMargin);
+ } else {
+ leftBound += mVideoCallIconSize + mVideoCallIconMargin;
+ }
+ }
+
+
+ // Center text vertically, then apply the top offset.
+ final int totalTextHeight = mNameTextViewHeight + mPhoneticNameTextViewHeight +
+ mLabelAndDataViewMaxHeight + mSnippetTextViewHeight + mStatusTextViewHeight;
+ int textTopBound = (bottomBound + topBound - totalTextHeight) / 2 + mTextOffsetTop;
+
+ // Work Profile icon align top
+ int workProfileIconWidth = 0;
+ if (isVisible(mWorkProfileIcon)) {
+ workProfileIconWidth = mWorkProfileIcon.getMeasuredWidth();
+ final int distanceFromEnd = mCheckBoxWidth > 0
+ ? mCheckBoxWidth + mGapBetweenImageAndText : 0;
+ if (mPhotoPosition == PhotoPosition.LEFT) {
+ // When photo is on left, label is placed on the right edge of the list item.
+ mWorkProfileIcon.layout(rightBound - workProfileIconWidth - distanceFromEnd,
+ textTopBound,
+ rightBound - distanceFromEnd,
+ textTopBound + mNameTextViewHeight);
+ } else {
+ // When photo is on right, label is placed on the left of data view.
+ mWorkProfileIcon.layout(leftBound + distanceFromEnd,
+ textTopBound,
+ leftBound + workProfileIconWidth + distanceFromEnd,
+ textTopBound + mNameTextViewHeight);
+ }
+ }
+
+ // Layout all text view and presence icon
+ // Put name TextView first
+ if (isVisible(mNameTextView)) {
+ final int distanceFromEnd = workProfileIconWidth
+ + (mCheckBoxWidth > 0 ? mCheckBoxWidth + mGapBetweenImageAndText : 0);
+ if (mPhotoPosition == PhotoPosition.LEFT) {
+ mNameTextView.layout(leftBound,
+ textTopBound,
+ rightBound - distanceFromEnd,
+ textTopBound + mNameTextViewHeight);
+ } else {
+ mNameTextView.layout(leftBound + distanceFromEnd,
+ textTopBound,
+ rightBound,
+ textTopBound + mNameTextViewHeight);
+ }
+ }
+
+ if (isVisible(mNameTextView) || isVisible(mWorkProfileIcon)) {
+ textTopBound += mNameTextViewHeight;
+ }
+
+ // Presence and status
+ if (isLayoutRtl) {
+ int statusRightBound = rightBound;
+ if (isVisible(mPresenceIcon)) {
+ int iconWidth = mPresenceIcon.getMeasuredWidth();
+ mPresenceIcon.layout(
+ rightBound - iconWidth,
+ textTopBound,
+ rightBound,
+ textTopBound + mStatusTextViewHeight);
+ statusRightBound -= (iconWidth + mPresenceIconMargin);
+ }
+
+ if (isVisible(mStatusView)) {
+ mStatusView.layout(leftBound,
+ textTopBound,
+ statusRightBound,
+ textTopBound + mStatusTextViewHeight);
+ }
+ } else {
+ int statusLeftBound = leftBound;
+ if (isVisible(mPresenceIcon)) {
+ int iconWidth = mPresenceIcon.getMeasuredWidth();
+ mPresenceIcon.layout(
+ leftBound,
+ textTopBound,
+ leftBound + iconWidth,
+ textTopBound + mStatusTextViewHeight);
+ statusLeftBound += (iconWidth + mPresenceIconMargin);
+ }
+
+ if (isVisible(mStatusView)) {
+ mStatusView.layout(statusLeftBound,
+ textTopBound,
+ rightBound,
+ textTopBound + mStatusTextViewHeight);
+ }
+ }
+
+ if (isVisible(mStatusView) || isVisible(mPresenceIcon)) {
+ textTopBound += mStatusTextViewHeight;
+ }
+
+ // Rest of text views
+ int dataLeftBound = leftBound;
+ if (isVisible(mPhoneticNameTextView)) {
+ mPhoneticNameTextView.layout(leftBound,
+ textTopBound,
+ rightBound,
+ textTopBound + mPhoneticNameTextViewHeight);
+ textTopBound += mPhoneticNameTextViewHeight;
+ }
+
+ // Label and Data align bottom.
+ if (isVisible(mLabelView)) {
+ if (!isLayoutRtl) {
+ mLabelView.layout(dataLeftBound,
+ textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
+ rightBound,
+ textTopBound + mLabelAndDataViewMaxHeight);
+ dataLeftBound += mLabelView.getMeasuredWidth() + mGapBetweenLabelAndData;
+ } else {
+ dataLeftBound = leftBound + mLabelView.getMeasuredWidth();
+ mLabelView.layout(rightBound - mLabelView.getMeasuredWidth(),
+ textTopBound + mLabelAndDataViewMaxHeight - mLabelViewHeight,
+ rightBound,
+ textTopBound + mLabelAndDataViewMaxHeight);
+ rightBound -= (mLabelView.getMeasuredWidth() + mGapBetweenLabelAndData);
+ }
+ }
+
+ if (isVisible(mDataView)) {
+ if (!isLayoutRtl) {
+ mDataView.layout(dataLeftBound,
+ textTopBound + mLabelAndDataViewMaxHeight - mDataViewHeight,
+ rightBound,
+ textTopBound + mLabelAndDataViewMaxHeight);
+ } else {
+ mDataView.layout(rightBound - mDataView.getMeasuredWidth(),
+ textTopBound + mLabelAndDataViewMaxHeight - mDataViewHeight,
+ rightBound,
+ textTopBound + mLabelAndDataViewMaxHeight);
+ }
+ }
+ if (isVisible(mLabelView) || isVisible(mDataView)) {
+ textTopBound += mLabelAndDataViewMaxHeight;
+ }
+
+ if (isVisible(mSnippetView)) {
+ mSnippetView.layout(leftBound,
+ textTopBound,
+ rightBound,
+ textTopBound + mSnippetTextViewHeight);
+ }
+ }
+
+ @Override
+ public void adjustListItemSelectionBounds(Rect bounds) {
+ if (mAdjustSelectionBoundsEnabled) {
+ bounds.top += mBoundsWithoutHeader.top;
+ bounds.bottom = bounds.top + mBoundsWithoutHeader.height();
+ bounds.left = mBoundsWithoutHeader.left;
+ bounds.right = mBoundsWithoutHeader.right;
+ }
+ }
+
+ protected boolean isVisible(View view) {
+ return view != null && view.getVisibility() == View.VISIBLE;
+ }
+
+ /**
+ * Extracts width and height from the style
+ */
+ private void ensurePhotoViewSize() {
+ if (!mPhotoViewWidthAndHeightAreReady) {
+ mPhotoViewWidth = mPhotoViewHeight = getDefaultPhotoViewSize();
+ if (!mQuickContactEnabled && mPhotoView == null) {
+ if (!mKeepHorizontalPaddingForPhotoView) {
+ mPhotoViewWidth = 0;
+ }
+ if (!mKeepVerticalPaddingForPhotoView) {
+ mPhotoViewHeight = 0;
+ }
+ }
+
+ mPhotoViewWidthAndHeightAreReady = true;
+ }
+ }
+
+ protected int getDefaultPhotoViewSize() {
+ return mDefaultPhotoViewSize;
+ }
+
+ /**
+ * Gets a LayoutParam that corresponds to the default photo size.
+ *
+ * @return A new LayoutParam.
+ */
+ private LayoutParams getDefaultPhotoLayoutParams() {
+ LayoutParams params = generateDefaultLayoutParams();
+ params.width = getDefaultPhotoViewSize();
+ params.height = params.width;
+ return params;
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ if (mActivatedStateSupported) {
+ mActivatedBackgroundDrawable.setState(getDrawableState());
+ }
+ }
+
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return who == mActivatedBackgroundDrawable || super.verifyDrawable(who);
+ }
+
+ @Override
+ public void jumpDrawablesToCurrentState() {
+ super.jumpDrawablesToCurrentState();
+ if (mActivatedStateSupported) {
+ mActivatedBackgroundDrawable.jumpToCurrentState();
+ }
+ }
+
+ @Override
+ public void dispatchDraw(Canvas canvas) {
+ if (mActivatedStateSupported && isActivated()) {
+ mActivatedBackgroundDrawable.draw(canvas);
+ }
+
+ super.dispatchDraw(canvas);
+ }
+
+ /**
+ * Sets section header or makes it invisible if the title is null.
+ */
+ public void setSectionHeader(String title) {
+ if (!TextUtils.isEmpty(title)) {
+ if (TextUtils.equals(getContext().getString(R.string.star_sign), title)) {
+ if (mHeaderView == null) {
+ addStarImageHeader();
+ } else if (mHeaderView instanceof TextView) {
+ removeView(mHeaderView);
+ addStarImageHeader();
+ } else {
+ mHeaderView.setVisibility(View.VISIBLE);
+ }
+ } else {
+ if (mHeaderView == null) {
+ addTextHeader(title);
+ } else if (mHeaderView instanceof ImageView) {
+ removeView(mHeaderView);
+ addTextHeader(title);
+ } else {
+ updateHeaderText((TextView) mHeaderView, title);
+ }
+ }
+ } else if (mHeaderView != null) {
+ mHeaderView.setVisibility(View.GONE);
+ }
+ }
+
+ private void addTextHeader(String title) {
+ mHeaderView = new TextView(getContext());
+ final TextView headerTextView = (TextView) mHeaderView;
+ headerTextView.setTextAppearance(getContext(), R.style.SectionHeaderStyle);
+ headerTextView.setGravity(Gravity.CENTER_HORIZONTAL);
+ updateHeaderText(headerTextView, title);
+ addView(headerTextView);
+ }
+
+ private void updateHeaderText(TextView headerTextView, String title) {
+ setMarqueeText(headerTextView, title);
+ headerTextView.setAllCaps(true);
+ if (ContactsSectionIndexer.BLANK_HEADER_STRING.equals(title)) {
+ headerTextView.setContentDescription(
+ getContext().getString(R.string.description_no_name_header));
+ } else {
+ headerTextView.setContentDescription(title);
+ }
+ headerTextView.setVisibility(View.VISIBLE);
+ }
+
+ private void addStarImageHeader() {
+ mHeaderView = new ImageView(getContext());
+ final ImageView headerImageView = (ImageView) mHeaderView;
+ headerImageView.setImageDrawable(
+ getResources().getDrawable(R.drawable.ic_material_star, getContext().getTheme()));
+ headerImageView.setImageTintList(ColorStateList.valueOf(getResources()
+ .getColor(R.color.material_star_pink)));
+ headerImageView.setContentDescription(
+ getContext().getString(R.string.list_filter_all_starred));
+ headerImageView.setVisibility(View.VISIBLE);
+ addView(headerImageView);
+ }
+
+ public void setIsSectionHeaderEnabled(boolean isSectionHeaderEnabled) {
+ mIsSectionHeaderEnabled = isSectionHeaderEnabled;
+ }
+
+ /**
+ * Returns the quick contact badge, creating it if necessary.
+ */
+ public QuickContactBadge getQuickContact() {
+ if (!mQuickContactEnabled) {
+ throw new IllegalStateException("QuickContact is disabled for this view");
+ }
+ if (mQuickContact == null) {
+ mQuickContact = new QuickContactBadge(getContext());
+ if (CompatUtils.isLollipopCompatible()) {
+ mQuickContact.setOverlay(null);
+ }
+ mQuickContact.setLayoutParams(getDefaultPhotoLayoutParams());
+ if (mNameTextView != null) {
+ mQuickContact.setContentDescription(getContext().getString(
+ R.string.description_quick_contact_for, mNameTextView.getText()));
+ }
+
+ addView(mQuickContact);
+ mPhotoViewWidthAndHeightAreReady = false;
+ }
+ return mQuickContact;
+ }
+
+ /**
+ * Returns the photo view, creating it if necessary.
+ */
+ public ImageView getPhotoView() {
+ if (mPhotoView == null) {
+ mPhotoView = new ImageView(getContext());
+ mPhotoView.setLayoutParams(getDefaultPhotoLayoutParams());
+ // Quick contact style used above will set a background - remove it
+ mPhotoView.setBackground(null);
+ addView(mPhotoView);
+ mPhotoViewWidthAndHeightAreReady = false;
+ }
+ return mPhotoView;
+ }
+
+ /**
+ * Removes the photo view.
+ */
+ public void removePhotoView() {
+ removePhotoView(false, true);
+ }
+
+ /**
+ * Removes the photo view.
+ *
+ * @param keepHorizontalPadding True means data on the right side will have
+ * padding on left, pretending there is still a photo view.
+ * @param keepVerticalPadding True means the View will have some height
+ * enough for accommodating a photo view.
+ */
+ public void removePhotoView(boolean keepHorizontalPadding, boolean keepVerticalPadding) {
+ mPhotoViewWidthAndHeightAreReady = false;
+ mKeepHorizontalPaddingForPhotoView = keepHorizontalPadding;
+ mKeepVerticalPaddingForPhotoView = keepVerticalPadding;
+ if (mPhotoView != null) {
+ removeView(mPhotoView);
+ mPhotoView = null;
+ }
+ if (mQuickContact != null) {
+ removeView(mQuickContact);
+ mQuickContact = null;
+ }
+ }
+
+ /**
+ * Sets a word prefix that will be highlighted if encountered in fields like
+ * name and search snippet. This will disable the mask highlighting for names.
+ * <p>
+ * NOTE: must be all upper-case
+ */
+ public void setHighlightedPrefix(String upperCasePrefix) {
+ mHighlightedPrefix = upperCasePrefix;
+ }
+
+ /**
+ * Clears previously set highlight sequences for the view.
+ */
+ public void clearHighlightSequences() {
+ mNameHighlightSequence.clear();
+ mNumberHighlightSequence.clear();
+ mHighlightedPrefix = null;
+ }
+
+ /**
+ * Adds a highlight sequence to the name highlighter.
+ * @param start The start position of the highlight sequence.
+ * @param end The end position of the highlight sequence.
+ */
+ public void addNameHighlightSequence(int start, int end) {
+ mNameHighlightSequence.add(new HighlightSequence(start, end));
+ }
+
+ /**
+ * Adds a highlight sequence to the number highlighter.
+ * @param start The start position of the highlight sequence.
+ * @param end The end position of the highlight sequence.
+ */
+ public void addNumberHighlightSequence(int start, int end) {
+ mNumberHighlightSequence.add(new HighlightSequence(start, end));
+ }
+
+ /**
+ * Returns the text view for the contact name, creating it if necessary.
+ */
+ public TextView getNameTextView() {
+ if (mNameTextView == null) {
+ mNameTextView = new TextView(getContext());
+ mNameTextView.setSingleLine(true);
+ mNameTextView.setEllipsize(getTextEllipsis());
+ mNameTextView.setTextColor(mNameTextViewTextColor);
+ mNameTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mNameTextViewTextSize);
+ // Manually call setActivated() since this view may be added after the first
+ // setActivated() call toward this whole item view.
+ mNameTextView.setActivated(isActivated());
+ mNameTextView.setGravity(Gravity.CENTER_VERTICAL);
+ mNameTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
+ mNameTextView.setId(R.id.cliv_name_textview);
+ if (CompatUtils.isLollipopCompatible()) {
+ mNameTextView.setElegantTextHeight(false);
+ }
+ addView(mNameTextView);
+ }
+ return mNameTextView;
+ }
+
+ /**
+ * Adds or updates a text view for the phonetic name.
+ */
+ public void setPhoneticName(char[] text, int size) {
+ if (text == null || size == 0) {
+ if (mPhoneticNameTextView != null) {
+ mPhoneticNameTextView.setVisibility(View.GONE);
+ }
+ } else {
+ getPhoneticNameTextView();
+ setMarqueeText(mPhoneticNameTextView, text, size);
+ mPhoneticNameTextView.setVisibility(VISIBLE);
+ }
+ }
+
+ /**
+ * Returns the text view for the phonetic name, creating it if necessary.
+ */
+ public TextView getPhoneticNameTextView() {
+ if (mPhoneticNameTextView == null) {
+ mPhoneticNameTextView = new TextView(getContext());
+ mPhoneticNameTextView.setSingleLine(true);
+ mPhoneticNameTextView.setEllipsize(getTextEllipsis());
+ mPhoneticNameTextView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
+ mPhoneticNameTextView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
+ mPhoneticNameTextView.setTypeface(mPhoneticNameTextView.getTypeface(), Typeface.BOLD);
+ mPhoneticNameTextView.setActivated(isActivated());
+ mPhoneticNameTextView.setId(R.id.cliv_phoneticname_textview);
+ addView(mPhoneticNameTextView);
+ }
+ return mPhoneticNameTextView;
+ }
+
+ /**
+ * Adds or updates a text view for the data label.
+ */
+ public void setLabel(CharSequence text) {
+ if (TextUtils.isEmpty(text)) {
+ if (mLabelView != null) {
+ mLabelView.setVisibility(View.GONE);
+ }
+ } else {
+ getLabelView();
+ setMarqueeText(mLabelView, text);
+ mLabelView.setVisibility(VISIBLE);
+ }
+ }
+
+ /**
+ * Returns the text view for the data label, creating it if necessary.
+ */
+ public TextView getLabelView() {
+ if (mLabelView == null) {
+ mLabelView = new TextView(getContext());
+ mLabelView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT));
+
+ mLabelView.setSingleLine(true);
+ mLabelView.setEllipsize(getTextEllipsis());
+ mLabelView.setTextAppearance(getContext(), R.style.TextAppearanceSmall);
+ if (mPhotoPosition == PhotoPosition.LEFT) {
+ mLabelView.setAllCaps(true);
+ } else {
+ mLabelView.setTypeface(mLabelView.getTypeface(), Typeface.BOLD);
+ }
+ mLabelView.setActivated(isActivated());
+ mLabelView.setId(R.id.cliv_label_textview);
+ addView(mLabelView);
+ }
+ return mLabelView;
+ }
+
+ /**
+ * Adds or updates a text view for the data element.
+ */
+ public void setData(char[] text, int size) {
+ if (text == null || size == 0) {
+ if (mDataView != null) {
+ mDataView.setVisibility(View.GONE);
+ }
+ } else {
+ getDataView();
+ setMarqueeText(mDataView, text, size);
+ mDataView.setVisibility(VISIBLE);
+ }
+ }
+
+ /**
+ * Sets phone number for a list item. This takes care of number highlighting if the highlight
+ * mask exists.
+ */
+ public void setPhoneNumber(String text, String countryIso) {
+ if (text == null) {
+ if (mDataView != null) {
+ mDataView.setVisibility(View.GONE);
+ }
+ } else {
+ getDataView();
+
+ // TODO: Format number using PhoneNumberUtils.formatNumber before assigning it to
+ // mDataView. Make sure that determination of the highlight sequences are done only
+ // after number formatting.
+
+ // Sets phone number texts for display after highlighting it, if applicable.
+ // CharSequence textToSet = text;
+ final SpannableString textToSet = new SpannableString(text);
+
+ if (mNumberHighlightSequence.size() != 0) {
+ final HighlightSequence highlightSequence = mNumberHighlightSequence.get(0);
+ mTextHighlighter.applyMaskingHighlight(textToSet, highlightSequence.start,
+ highlightSequence.end);
+ }
+
+ setMarqueeText(mDataView, textToSet);
+ mDataView.setVisibility(VISIBLE);
+
+ // We have a phone number as "mDataView" so make it always LTR and VIEW_START
+ mDataView.setTextDirection(View.TEXT_DIRECTION_LTR);
+ mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
+ }
+ }
+
+ private void setMarqueeText(TextView textView, char[] text, int size) {
+ if (getTextEllipsis() == TruncateAt.MARQUEE) {
+ setMarqueeText(textView, new String(text, 0, size));
+ } else {
+ textView.setText(text, 0, size);
+ }
+ }
+
+ private void setMarqueeText(TextView textView, CharSequence text) {
+ if (getTextEllipsis() == TruncateAt.MARQUEE) {
+ // To show MARQUEE correctly (with END effect during non-active state), we need
+ // to build Spanned with MARQUEE in addition to TextView's ellipsize setting.
+ final SpannableString spannable = new SpannableString(text);
+ spannable.setSpan(TruncateAt.MARQUEE, 0, spannable.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ textView.setText(spannable);
+ } else {
+ textView.setText(text);
+ }
+ }
+
+ /**
+ * Returns the {@link AppCompatCheckBox} view, creating it if necessary.
+ */
+ public AppCompatCheckBox getCheckBox() {
+ if (mCheckBox == null) {
+ mCheckBox = new AppCompatCheckBox(getContext());
+ // Make non-focusable, so the rest of the ContactListItemView can be clicked.
+ mCheckBox.setFocusable(false);
+ addView(mCheckBox);
+ }
+ return mCheckBox;
+ }
+
+ /**
+ * Returns the {@link AppCompatImageButton} delete button, creating it if necessary.
+ */
+ public AppCompatImageButton getDeleteImageButton(
+ final MultiSelectEntryContactListAdapter.DeleteContactListener listener,
+ final int position) {
+ if (mDeleteImageButton == null) {
+ mDeleteImageButton = new AppCompatImageButton(getContext());
+ mDeleteImageButton.setImageResource(R.drawable.ic_cancel_black_24dp);
+ mDeleteImageButton.setScaleType(ScaleType.CENTER);
+ mDeleteImageButton.setBackgroundColor(Color.TRANSPARENT);
+ mDeleteImageButton.setContentDescription(
+ getResources().getString(R.string.description_delete_contact));
+ if (CompatUtils. isLollipopCompatible()) {
+ final TypedValue typedValue = new TypedValue();
+ getContext().getTheme().resolveAttribute(
+ android.R.attr.selectableItemBackgroundBorderless, typedValue, true);
+ mDeleteImageButton.setBackgroundResource(typedValue.resourceId);
+ }
+ addView(mDeleteImageButton);
+ }
+ // Reset onClickListener because after reloading the view, position might be changed.
+ mDeleteImageButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Inform the adapter that delete icon was clicked.
+ if (listener != null) {
+ listener.onContactDeleteClicked(position);
+ }
+ }
+ });
+ return mDeleteImageButton;
+ }
+
+ /**
+ * Returns the text view for the data text, creating it if necessary.
+ */
+ public TextView getDataView() {
+ if (mDataView == null) {
+ mDataView = new TextView(getContext());
+ mDataView.setSingleLine(true);
+ mDataView.setEllipsize(getTextEllipsis());
+ mDataView.setTextAppearance(getContext(), R.style.TextAppearanceSmall);
+ mDataView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
+ mDataView.setActivated(isActivated());
+ mDataView.setId(R.id.cliv_data_view);
+ if (CompatUtils.isLollipopCompatible()) {
+ mDataView.setElegantTextHeight(false);
+ }
+ addView(mDataView);
+ }
+ return mDataView;
+ }
+
+ /**
+ * Adds or updates a text view for the search snippet.
+ */
+ public void setSnippet(String text) {
+ if (TextUtils.isEmpty(text)) {
+ if (mSnippetView != null) {
+ mSnippetView.setVisibility(View.GONE);
+ }
+ } else {
+ mTextHighlighter.setPrefixText(getSnippetView(), text, mHighlightedPrefix);
+ mSnippetView.setVisibility(VISIBLE);
+ if (ContactDisplayUtils.isPossiblePhoneNumber(text)) {
+ // Give the text-to-speech engine a hint that it's a phone number
+ mSnippetView.setContentDescription(
+ PhoneNumberUtilsCompat.createTtsSpannable(text));
+ } else {
+ mSnippetView.setContentDescription(null);
+ }
+ }
+ }
+
+ /**
+ * Returns the text view for the search snippet, creating it if necessary.
+ */
+ public TextView getSnippetView() {
+ if (mSnippetView == null) {
+ mSnippetView = new TextView(getContext());
+ mSnippetView.setSingleLine(true);
+ mSnippetView.setEllipsize(getTextEllipsis());
+ mSnippetView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
+ mSnippetView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
+ mSnippetView.setActivated(isActivated());
+ addView(mSnippetView);
+ }
+ return mSnippetView;
+ }
+
+ /**
+ * Returns the text view for the status, creating it if necessary.
+ */
+ public TextView getStatusView() {
+ if (mStatusView == null) {
+ mStatusView = new TextView(getContext());
+ mStatusView.setSingleLine(true);
+ mStatusView.setEllipsize(getTextEllipsis());
+ mStatusView.setTextAppearance(getContext(), android.R.style.TextAppearance_Small);
+ mStatusView.setTextColor(mSecondaryTextColor);
+ mStatusView.setActivated(isActivated());
+ mStatusView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
+ addView(mStatusView);
+ }
+ return mStatusView;
+ }
+
+ /**
+ * Adds or updates a text view for the status.
+ */
+ public void setStatus(CharSequence text) {
+ if (TextUtils.isEmpty(text)) {
+ if (mStatusView != null) {
+ mStatusView.setVisibility(View.GONE);
+ }
+ } else {
+ getStatusView();
+ setMarqueeText(mStatusView, text);
+ mStatusView.setVisibility(VISIBLE);
+ }
+ }
+
+ /**
+ * Adds or updates the presence icon view.
+ */
+ public void setPresence(Drawable icon) {
+ if (icon != null) {
+ if (mPresenceIcon == null) {
+ mPresenceIcon = new ImageView(getContext());
+ addView(mPresenceIcon);
+ }
+ mPresenceIcon.setImageDrawable(icon);
+ mPresenceIcon.setScaleType(ScaleType.CENTER);
+ mPresenceIcon.setVisibility(View.VISIBLE);
+ } else {
+ if (mPresenceIcon != null) {
+ mPresenceIcon.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ /**
+ * Set to display work profile icon or not
+ *
+ * @param enabled set to display work profile icon or not
+ */
+ public void setWorkProfileIconEnabled(boolean enabled) {
+ if (mWorkProfileIcon != null) {
+ mWorkProfileIcon.setVisibility(enabled ? View.VISIBLE : View.GONE);
+ } else if (enabled) {
+ mWorkProfileIcon = new ImageView(getContext());
+ addView(mWorkProfileIcon);
+ mWorkProfileIcon.setImageResource(R.drawable.ic_work_profile);
+ mWorkProfileIcon.setScaleType(ScaleType.CENTER_INSIDE);
+ mWorkProfileIcon.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private TruncateAt getTextEllipsis() {
+ return TruncateAt.MARQUEE;
+ }
+
+ public void showDisplayName(Cursor cursor, int nameColumnIndex, int displayOrder) {
+ CharSequence name = cursor.getString(nameColumnIndex);
+ setDisplayName(name);
+
+ // Since the quick contact content description is derived from the display name and there is
+ // no guarantee that when the quick contact is initialized the display name is already set,
+ // do it here too.
+ if (mQuickContact != null) {
+ mQuickContact.setContentDescription(getContext().getString(
+ R.string.description_quick_contact_for, mNameTextView.getText()));
+ }
+ }
+
+ public void setDisplayName(CharSequence name, boolean highlight) {
+ if (!TextUtils.isEmpty(name) && highlight) {
+ clearHighlightSequences();
+ addNameHighlightSequence(0, name.length());
+ }
+ setDisplayName(name);
+ }
+
+ public void setDisplayName(CharSequence name) {
+ if (!TextUtils.isEmpty(name)) {
+ // Chooses the available highlighting method for highlighting.
+ if (mHighlightedPrefix != null) {
+ name = mTextHighlighter.applyPrefixHighlight(name, mHighlightedPrefix);
+ } else if (mNameHighlightSequence.size() != 0) {
+ final SpannableString spannableName = new SpannableString(name);
+ for (HighlightSequence highlightSequence : mNameHighlightSequence) {
+ mTextHighlighter.applyMaskingHighlight(spannableName, highlightSequence.start,
+ highlightSequence.end);
+ }
+ name = spannableName;
+ }
+ } else {
+ name = mUnknownNameText;
+ }
+ setMarqueeText(getNameTextView(), name);
+
+ if (ContactDisplayUtils.isPossiblePhoneNumber(name)) {
+ // Give the text-to-speech engine a hint that it's a phone number
+ mNameTextView.setTextDirection(View.TEXT_DIRECTION_LTR);
+ mNameTextView.setContentDescription(
+ PhoneNumberUtilsCompat.createTtsSpannable(name.toString()));
+ } else {
+ // Remove span tags of highlighting for talkback to avoid reading highlighting and rest
+ // of the name into two separate parts.
+ mNameTextView.setContentDescription(name.toString());
+ }
+ }
+
+ public void hideCheckBox() {
+ if (mCheckBox != null) {
+ removeView(mCheckBox);
+ mCheckBox = null;
+ }
+ }
+
+ public void hideDeleteImageButton() {
+ if (mDeleteImageButton != null) {
+ removeView(mDeleteImageButton);
+ mDeleteImageButton = null;
+ }
+ }
+
+ public void hideDisplayName() {
+ if (mNameTextView != null) {
+ removeView(mNameTextView);
+ mNameTextView = null;
+ }
+ }
+
+ public void showPhoneticName(Cursor cursor, int phoneticNameColumnIndex) {
+ cursor.copyStringToBuffer(phoneticNameColumnIndex, mPhoneticNameBuffer);
+ int phoneticNameSize = mPhoneticNameBuffer.sizeCopied;
+ if (phoneticNameSize != 0) {
+ setPhoneticName(mPhoneticNameBuffer.data, phoneticNameSize);
+ } else {
+ setPhoneticName(null, 0);
+ }
+ }
+
+ public void hidePhoneticName() {
+ if (mPhoneticNameTextView != null) {
+ removeView(mPhoneticNameTextView);
+ mPhoneticNameTextView = null;
+ }
+ }
+
+ /**
+ * Sets the proper icon (star or presence or nothing) and/or status message.
+ */
+ public void showPresenceAndStatusMessage(Cursor cursor, int presenceColumnIndex,
+ int contactStatusColumnIndex) {
+ Drawable icon = null;
+ int presence = 0;
+ if (!cursor.isNull(presenceColumnIndex)) {
+ presence = cursor.getInt(presenceColumnIndex);
+ icon = ContactPresenceIconUtil.getPresenceIcon(getContext(), presence);
+ }
+ setPresence(icon);
+
+ String statusMessage = null;
+ if (contactStatusColumnIndex != 0 && !cursor.isNull(contactStatusColumnIndex)) {
+ statusMessage = cursor.getString(contactStatusColumnIndex);
+ }
+ // If there is no status message from the contact, but there was a presence value, then use
+ // the default status message string
+ if (statusMessage == null && presence != 0) {
+ statusMessage = ContactStatusUtil.getStatusString(getContext(), presence);
+ }
+ setStatus(statusMessage);
+ }
+
+ /**
+ * Shows search snippet for email and phone number matches.
+ */
+ public void showSnippet(Cursor cursor, String query, int snippetColumn) {
+ // TODO: this does not properly handle phone numbers with control characters
+ // For example if the phone number is 444-5555, the search query 4445 will match the
+ // number since we normalize it before querying CP2 but the snippet will fail since
+ // the portion to be highlighted is 444-5 not 4445.
+ final String snippet = cursor.getString(snippetColumn);
+ if (snippet == null) {
+ setSnippet(null);
+ return;
+ }
+ final String displayName = cursor.getColumnIndex(Contacts.DISPLAY_NAME) >= 0
+ ? cursor.getString(cursor.getColumnIndex(Contacts.DISPLAY_NAME)) : null;
+ if (snippet.equals(displayName)) {
+ // If the snippet exactly matches the display name (i.e. the phone number or email
+ // address is being used as the display name) then no snippet is necessary
+ setSnippet(null);
+ return;
+ }
+ // Show the snippet with the part of the query that matched it
+ setSnippet(updateSnippet(snippet, query, displayName));
+ }
+
+ /**
+ * Shows search snippet.
+ */
+ public void showSnippet(Cursor cursor, int summarySnippetColumnIndex) {
+ if (cursor.getColumnCount() <= summarySnippetColumnIndex
+ || !SearchSnippets.SNIPPET.equals(cursor.getColumnName(summarySnippetColumnIndex))) {
+ setSnippet(null);
+ return;
+ }
+
+ String snippet = cursor.getString(summarySnippetColumnIndex);
+
+ // Do client side snippeting if provider didn't do it
+ final Bundle extras = cursor.getExtras();
+ if (extras.getBoolean(ContactsContract.DEFERRED_SNIPPETING)) {
+
+ final String query = extras.getString(ContactsContract.DEFERRED_SNIPPETING_QUERY);
+
+ String displayName = null;
+ int displayNameIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
+ if (displayNameIndex >= 0) {
+ displayName = cursor.getString(displayNameIndex);
+ }
+
+ snippet = updateSnippet(snippet, query, displayName);
+
+ } else {
+ if (snippet != null) {
+ int from = 0;
+ int to = snippet.length();
+ int start = snippet.indexOf(DefaultContactListAdapter.SNIPPET_START_MATCH);
+ if (start == -1) {
+ snippet = null;
+ } else {
+ int firstNl = snippet.lastIndexOf('\n', start);
+ if (firstNl != -1) {
+ from = firstNl + 1;
+ }
+ int end = snippet.lastIndexOf(DefaultContactListAdapter.SNIPPET_END_MATCH);
+ if (end != -1) {
+ int lastNl = snippet.indexOf('\n', end);
+ if (lastNl != -1) {
+ to = lastNl;
+ }
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = from; i < to; i++) {
+ char c = snippet.charAt(i);
+ if (c != DefaultContactListAdapter.SNIPPET_START_MATCH &&
+ c != DefaultContactListAdapter.SNIPPET_END_MATCH) {
+ sb.append(c);
+ }
+ }
+ snippet = sb.toString();
+ }
+ }
+ }
+
+ setSnippet(snippet);
+ }
+
+ /**
+ * Used for deferred snippets from the database. The contents come back as large strings which
+ * need to be extracted for display.
+ *
+ * @param snippet The snippet from the database.
+ * @param query The search query substring.
+ * @param displayName The contact display name.
+ * @return The proper snippet to display.
+ */
+ private String updateSnippet(String snippet, String query, String displayName) {
+
+ if (TextUtils.isEmpty(snippet) || TextUtils.isEmpty(query)) {
+ return null;
+ }
+ query = SearchUtil.cleanStartAndEndOfSearchQuery(query.toLowerCase());
+
+ // If the display name already contains the query term, return empty - snippets should
+ // not be needed in that case.
+ if (!TextUtils.isEmpty(displayName)) {
+ final String lowerDisplayName = displayName.toLowerCase();
+ final List<String> nameTokens = split(lowerDisplayName);
+ for (String nameToken : nameTokens) {
+ if (nameToken.startsWith(query)) {
+ return null;
+ }
+ }
+ }
+
+ // The snippet may contain multiple data lines.
+ // Show the first line that matches the query.
+ final SearchUtil.MatchedLine matched = SearchUtil.findMatchingLine(snippet, query);
+
+ if (matched != null && matched.line != null) {
+ // Tokenize for long strings since the match may be at the end of it.
+ // Skip this part for short strings since the whole string will be displayed.
+ // Most contact strings are short so the snippetize method will be called infrequently.
+ final int lengthThreshold = getResources().getInteger(
+ R.integer.snippet_length_before_tokenize);
+ if (matched.line.length() > lengthThreshold) {
+ return snippetize(matched.line, matched.startIndex, lengthThreshold);
+ } else {
+ return matched.line;
+ }
+ }
+
+ // No match found.
+ return null;
+ }
+
+ private String snippetize(String line, int matchIndex, int maxLength) {
+ // Show up to maxLength characters. But we only show full tokens so show the last full token
+ // up to maxLength characters. So as many starting tokens as possible before trying ending
+ // tokens.
+ int remainingLength = maxLength;
+ int tempRemainingLength = remainingLength;
+
+ // Start the end token after the matched query.
+ int index = matchIndex;
+ int endTokenIndex = index;
+
+ // Find the match token first.
+ while (index < line.length()) {
+ if (!Character.isLetterOrDigit(line.charAt(index))) {
+ endTokenIndex = index;
+ remainingLength = tempRemainingLength;
+ break;
+ }
+ tempRemainingLength--;
+ index++;
+ }
+
+ // Find as much content before the match.
+ index = matchIndex - 1;
+ tempRemainingLength = remainingLength;
+ int startTokenIndex = matchIndex;
+ while (index > -1 && tempRemainingLength > 0) {
+ if (!Character.isLetterOrDigit(line.charAt(index))) {
+ startTokenIndex = index;
+ remainingLength = tempRemainingLength;
+ }
+ tempRemainingLength--;
+ index--;
+ }
+
+ index = endTokenIndex;
+ tempRemainingLength = remainingLength;
+ // Find remaining content at after match.
+ while (index < line.length() && tempRemainingLength > 0) {
+ if (!Character.isLetterOrDigit(line.charAt(index))) {
+ endTokenIndex = index;
+ }
+ tempRemainingLength--;
+ index++;
+ }
+ // Append ellipse if there is content before or after.
+ final StringBuilder sb = new StringBuilder();
+ if (startTokenIndex > 0) {
+ sb.append("...");
+ }
+ sb.append(line.substring(startTokenIndex, endTokenIndex));
+ if (endTokenIndex < line.length()) {
+ sb.append("...");
+ }
+ return sb.toString();
+ }
+
+ private static final Pattern SPLIT_PATTERN = Pattern.compile(
+ "([\\w-\\.]+)@((?:[\\w]+\\.)+)([a-zA-Z]{2,4})|[\\w]+");
+
+ /**
+ * Helper method for splitting a string into tokens. The lists passed in are populated with
+ * the
+ * tokens and offsets into the content of each token. The tokenization function parses e-mail
+ * addresses as a single token; otherwise it splits on any non-alphanumeric character.
+ *
+ * @param content Content to split.
+ * @return List of token strings.
+ */
+ private static List<String> split(String content) {
+ final Matcher matcher = SPLIT_PATTERN.matcher(content);
+ final ArrayList<String> tokens = Lists.newArrayList();
+ while (matcher.find()) {
+ tokens.add(matcher.group());
+ }
+ return tokens;
+ }
+
+ /**
+ * Shows data element.
+ */
+ public void showData(Cursor cursor, int dataColumnIndex) {
+ cursor.copyStringToBuffer(dataColumnIndex, mDataBuffer);
+ setData(mDataBuffer.data, mDataBuffer.sizeCopied);
+ }
+
+ public void setActivatedStateSupported(boolean flag) {
+ this.mActivatedStateSupported = flag;
+ }
+
+ public void setAdjustSelectionBoundsEnabled(boolean enabled) {
+ mAdjustSelectionBoundsEnabled = enabled;
+ }
+
+ @Override
+ public void requestLayout() {
+ // We will assume that once measured this will not need to resize
+ // itself, so there is no need to pass the layout request to the parent
+ // view (ListView).
+ forceLayout();
+ }
+
+ public void setPhotoPosition(PhotoPosition photoPosition) {
+ mPhotoPosition = photoPosition;
+ }
+
+ public PhotoPosition getPhotoPosition() {
+ return mPhotoPosition;
+ }
+
+ /**
+ * Set drawable resources directly for the drawable resource of the photo view.
+ *
+ * @param drawableId Id of drawable resource.
+ */
+ public void setDrawableResource(int drawableId) {
+ ImageView photo = getPhotoView();
+ photo.setScaleType(ImageView.ScaleType.CENTER);
+ final Drawable drawable = ContextCompat.getDrawable(getContext(), drawableId);
+ final int iconColor =
+ ContextCompat.getColor(getContext(), R.color.search_shortcut_icon_color);
+ if (CompatUtils.isLollipopCompatible()) {
+ photo.setImageDrawable(drawable);
+ photo.setImageTintList(ColorStateList.valueOf(iconColor));
+ } else {
+ final Drawable drawableWrapper = DrawableCompat.wrap(drawable).mutate();
+ DrawableCompat.setTint(drawableWrapper, iconColor);
+ photo.setImageDrawable(drawableWrapper);
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ final float x = event.getX();
+ final float y = event.getY();
+ // If the touch event's coordinates are not within the view's header, then delegate
+ // to super.onTouchEvent so that regular view behavior is preserved. Otherwise, consume
+ // and ignore the touch event.
+ if (mBoundsWithoutHeader.contains((int) x, (int) y) || !pointIsInView(x, y)) {
+ return super.onTouchEvent(event);
+ } else {
+ return true;
+ }
+ }
+
+ private final boolean pointIsInView(float localX, float localY) {
+ return localX >= mLeftOffset && localX < mRightOffset
+ && localY >= 0 && localY < (getBottom() - getTop());
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java b/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
new file mode 100644
index 0000000..6e8e738
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactListPinnedHeaderView.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewParent;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.TextView;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.util.ViewUtil;
+
+/**
+ * A custom view for the pinned section header shown at the top of the contact list.
+ */
+public class ContactListPinnedHeaderView extends TextView {
+
+ public ContactListPinnedHeaderView(Context context, AttributeSet attrs, View parent) {
+ super(context, attrs);
+
+ if (R.styleable.ContactListItemView == null) {
+ return;
+ }
+ TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ContactListItemView);
+ int backgroundColor = a.getColor(
+ R.styleable.ContactListItemView_list_item_background_color, Color.WHITE);
+ int textOffsetTop = a.getDimensionPixelSize(
+ R.styleable.ContactListItemView_list_item_text_offset_top, 0);
+ int paddingStartOffset = a.getDimensionPixelSize(
+ R.styleable.ContactListItemView_list_item_padding_left, 0);
+ int textWidth = getResources().getDimensionPixelSize(
+ R.dimen.contact_list_section_header_width);
+ int widthIncludingPadding = paddingStartOffset + textWidth;
+ a.recycle();
+
+ setBackgroundColor(backgroundColor);
+ setTextAppearance(getContext(), R.style.SectionHeaderStyle);
+ setLayoutParams(new LayoutParams(widthIncludingPadding, LayoutParams.WRAP_CONTENT));
+ setLayoutDirection(parent.getLayoutDirection());
+ setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
+
+ // Apply text top offset. Multiply by two, because we are implementing this by padding for a
+ // vertically centered view, rather than adjusting the position directly via a layout.
+ setPaddingRelative(
+ getPaddingStart() + paddingStartOffset,
+ getPaddingTop() + (textOffsetTop * 2),
+ getPaddingEnd(),
+ getPaddingBottom());
+ }
+
+ /**
+ * Sets section header or makes it invisible if the title is null.
+ */
+ public void setSectionHeaderTitle(String title) {
+ if (!TextUtils.isEmpty(title)) {
+ setText(title);
+ setVisibility(View.VISIBLE);
+ } else {
+ setVisibility(View.GONE);
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactTileAdapter.java b/src/com/android/contacts/common/list/ContactTileAdapter.java
new file mode 100644
index 0000000..6ce4efb
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactTileAdapter.java
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 2011 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.common.list;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.ContactPresenceIconUtil;
+import com.android.contacts.common.ContactStatusUtil;
+import com.android.contacts.common.ContactTileLoaderFactory;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.R;
+import com.android.contacts.common.util.ViewUtil;
+
+import java.util.ArrayList;
+
+/**
+ * Arranges contacts favorites according to provided {@link DisplayType}.
+ * Also allows for a configurable number of columns and {@link DisplayType}
+ */
+public class ContactTileAdapter extends BaseAdapter {
+ private static final String TAG = ContactTileAdapter.class.getSimpleName();
+
+ private DisplayType mDisplayType;
+ private ContactTileView.Listener mListener;
+ private Context mContext;
+ private Resources mResources;
+ protected Cursor mContactCursor = null;
+ private ContactPhotoManager mPhotoManager;
+ protected int mNumFrequents;
+
+ /**
+ * Index of the first NON starred contact in the {@link Cursor}
+ * Only valid when {@link DisplayType#STREQUENT} is true
+ */
+ private int mDividerPosition;
+ protected int mColumnCount;
+ private int mStarredIndex;
+
+ protected int mIdIndex;
+ protected int mLookupIndex;
+ protected int mPhotoUriIndex;
+ protected int mNameIndex;
+ protected int mPresenceIndex;
+ protected int mStatusIndex;
+
+ private boolean mIsQuickContactEnabled = false;
+ private final int mPaddingInPixels;
+ private final int mWhitespaceStartEnd;
+
+ /**
+ * Configures the adapter to filter and display contacts using different view types.
+ * TODO: Create Uris to support getting Starred_only and Frequent_only cursors.
+ */
+ public enum DisplayType {
+ /**
+ * Displays a mixed view type of starred and frequent contacts
+ */
+ STREQUENT,
+
+ /**
+ * Display only starred contacts
+ */
+ STARRED_ONLY,
+
+ /**
+ * Display only most frequently contacted
+ */
+ FREQUENT_ONLY,
+
+ /**
+ * Display all contacts from a group in the cursor
+ */
+ GROUP_MEMBERS
+ }
+
+ public ContactTileAdapter(Context context, ContactTileView.Listener listener, int numCols,
+ DisplayType displayType) {
+ mListener = listener;
+ mContext = context;
+ mResources = context.getResources();
+ mColumnCount = (displayType == DisplayType.FREQUENT_ONLY ? 1 : numCols);
+ mDisplayType = displayType;
+ mNumFrequents = 0;
+
+ // Converting padding in dips to padding in pixels
+ mPaddingInPixels = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.contact_tile_divider_padding);
+ mWhitespaceStartEnd = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.contact_tile_start_end_whitespace);
+
+ bindColumnIndices();
+ }
+
+ public void setPhotoLoader(ContactPhotoManager photoLoader) {
+ mPhotoManager = photoLoader;
+ }
+
+ public void setColumnCount(int columnCount) {
+ mColumnCount = columnCount;
+ }
+
+ public void setDisplayType(DisplayType displayType) {
+ mDisplayType = displayType;
+ }
+
+ public void enableQuickContact(boolean enableQuickContact) {
+ mIsQuickContactEnabled = enableQuickContact;
+ }
+
+ /**
+ * Sets the column indices for expected {@link Cursor}
+ * based on {@link DisplayType}.
+ */
+ protected void bindColumnIndices() {
+ mIdIndex = ContactTileLoaderFactory.CONTACT_ID;
+ mLookupIndex = ContactTileLoaderFactory.LOOKUP_KEY;
+ mPhotoUriIndex = ContactTileLoaderFactory.PHOTO_URI;
+ mNameIndex = ContactTileLoaderFactory.DISPLAY_NAME;
+ mStarredIndex = ContactTileLoaderFactory.STARRED;
+ mPresenceIndex = ContactTileLoaderFactory.CONTACT_PRESENCE;
+ mStatusIndex = ContactTileLoaderFactory.CONTACT_STATUS;
+ }
+
+ private static boolean cursorIsValid(Cursor cursor) {
+ return cursor != null && !cursor.isClosed();
+ }
+
+ /**
+ * Gets the number of frequents from the passed in cursor.
+ *
+ * This methods is needed so the GroupMemberTileAdapter can override this.
+ *
+ * @param cursor The cursor to get number of frequents from.
+ */
+ protected void saveNumFrequentsFromCursor(Cursor cursor) {
+
+ // count the number of frequents
+ switch (mDisplayType) {
+ case STARRED_ONLY:
+ mNumFrequents = 0;
+ break;
+ case STREQUENT:
+ mNumFrequents = cursorIsValid(cursor) ?
+ cursor.getCount() - mDividerPosition : 0;
+ break;
+ case FREQUENT_ONLY:
+ mNumFrequents = cursorIsValid(cursor) ? cursor.getCount() : 0;
+ break;
+ default:
+ throw new IllegalArgumentException("Unrecognized DisplayType " + mDisplayType);
+ }
+ }
+
+ /**
+ * Creates {@link ContactTileView}s for each item in {@link Cursor}.
+ *
+ * Else use {@link ContactTileLoaderFactory}
+ */
+ public void setContactCursor(Cursor cursor) {
+ mContactCursor = cursor;
+ mDividerPosition = getDividerPosition(cursor);
+
+ saveNumFrequentsFromCursor(cursor);
+
+ // cause a refresh of any views that rely on this data
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Iterates over the {@link Cursor}
+ * Returns position of the first NON Starred Contact
+ * Returns -1 if {@link DisplayType#STARRED_ONLY}
+ * Returns 0 if {@link DisplayType#FREQUENT_ONLY}
+ */
+ protected int getDividerPosition(Cursor cursor) {
+ switch (mDisplayType) {
+ case STREQUENT:
+ if (!cursorIsValid(cursor)) {
+ return 0;
+ }
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ if (cursor.getInt(mStarredIndex) == 0) {
+ return cursor.getPosition();
+ }
+ }
+
+ // There are not NON Starred contacts in cursor
+ // Set divider positon to end
+ return cursor.getCount();
+ case STARRED_ONLY:
+ // There is no divider
+ return -1;
+ case FREQUENT_ONLY:
+ // Divider is first
+ return 0;
+ default:
+ throw new IllegalStateException("Unrecognized DisplayType " + mDisplayType);
+ }
+ }
+
+ protected ContactEntry createContactEntryFromCursor(Cursor cursor, int position) {
+ // If the loader was canceled we will be given a null cursor.
+ // In that case, show an empty list of contacts.
+ if (!cursorIsValid(cursor) || cursor.getCount() <= position) {
+ return null;
+ }
+
+ cursor.moveToPosition(position);
+ long id = cursor.getLong(mIdIndex);
+ String photoUri = cursor.getString(mPhotoUriIndex);
+ String lookupKey = cursor.getString(mLookupIndex);
+
+ ContactEntry contact = new ContactEntry();
+ String name = cursor.getString(mNameIndex);
+ contact.namePrimary = (name != null) ? name : mResources.getString(R.string.missing_name);
+ contact.status = cursor.getString(mStatusIndex);
+ contact.photoUri = (photoUri != null ? Uri.parse(photoUri) : null);
+ contact.lookupKey = lookupKey;
+ contact.lookupUri = ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id);
+ contact.isFavorite = cursor.getInt(mStarredIndex) > 0;
+
+ // Set presence icon and status message
+ Drawable icon = null;
+ int presence = 0;
+ if (!cursor.isNull(mPresenceIndex)) {
+ presence = cursor.getInt(mPresenceIndex);
+ icon = ContactPresenceIconUtil.getPresenceIcon(mContext, presence);
+ }
+ contact.presenceIcon = icon;
+
+ String statusMessage = null;
+ if (mStatusIndex != 0 && !cursor.isNull(mStatusIndex)) {
+ statusMessage = cursor.getString(mStatusIndex);
+ }
+ // If there is no status message from the contact, but there was a presence value,
+ // then use the default status message string
+ if (statusMessage == null && presence != 0) {
+ statusMessage = ContactStatusUtil.getStatusString(mContext, presence);
+ }
+ contact.status = statusMessage;
+
+ return contact;
+ }
+
+ /**
+ * Returns the number of frequents that will be displayed in the list.
+ */
+ public int getNumFrequents() {
+ return mNumFrequents;
+ }
+
+ @Override
+ public int getCount() {
+ if (!cursorIsValid(mContactCursor)) {
+ return 0;
+ }
+
+ switch (mDisplayType) {
+ case STARRED_ONLY:
+ return getRowCount(mContactCursor.getCount());
+ case STREQUENT:
+ // Takes numbers of rows the Starred Contacts Occupy
+ int starredRowCount = getRowCount(mDividerPosition);
+
+ // Compute the frequent row count which is 1 plus the number of frequents
+ // (to account for the divider) or 0 if there are no frequents.
+ int frequentRowCount = mNumFrequents == 0 ? 0 : mNumFrequents + 1;
+
+ // Return the number of starred plus frequent rows
+ return starredRowCount + frequentRowCount;
+ case FREQUENT_ONLY:
+ // Number of frequent contacts
+ return mContactCursor.getCount();
+ default:
+ throw new IllegalArgumentException("Unrecognized DisplayType " + mDisplayType);
+ }
+ }
+
+ /**
+ * Returns the number of rows required to show the provided number of entries
+ * with the current number of columns.
+ */
+ protected int getRowCount(int entryCount) {
+ return entryCount == 0 ? 0 : ((entryCount - 1) / mColumnCount) + 1;
+ }
+
+ public int getColumnCount() {
+ return mColumnCount;
+ }
+
+ /**
+ * Returns an ArrayList of the {@link ContactEntry}s that are to appear
+ * on the row for the given position.
+ */
+ @Override
+ public ArrayList<ContactEntry> getItem(int position) {
+ ArrayList<ContactEntry> resultList = new ArrayList<ContactEntry>(mColumnCount);
+ int contactIndex = position * mColumnCount;
+
+ switch (mDisplayType) {
+ case FREQUENT_ONLY:
+ resultList.add(createContactEntryFromCursor(mContactCursor, position));
+ break;
+ case STARRED_ONLY:
+ for (int columnCounter = 0; columnCounter < mColumnCount; columnCounter++) {
+ resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
+ contactIndex++;
+ }
+ break;
+ case STREQUENT:
+ if (position < getRowCount(mDividerPosition)) {
+ for (int columnCounter = 0; columnCounter < mColumnCount &&
+ contactIndex != mDividerPosition; columnCounter++) {
+ resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
+ contactIndex++;
+ }
+ } else {
+ /*
+ * Current position minus how many rows are before the divider and
+ * Minus 1 for the divider itself provides the relative index of the frequent
+ * contact being displayed. Then add the dividerPostion to give the offset
+ * into the contacts cursor to get the absoulte index.
+ */
+ contactIndex = position - getRowCount(mDividerPosition) - 1 + mDividerPosition;
+ resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
+ }
+ break;
+ default:
+ throw new IllegalStateException("Unrecognized DisplayType " + mDisplayType);
+ }
+ return resultList;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ // As we show several selectable items for each ListView row,
+ // we can not determine a stable id. But as we don't rely on ListView's selection,
+ // this should not be a problem.
+ return position;
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return (mDisplayType != DisplayType.STREQUENT);
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return position != getRowCount(mDividerPosition);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ int itemViewType = getItemViewType(position);
+
+ if (itemViewType == ViewTypes.DIVIDER) {
+ // Checking For Divider First so not to cast convertView
+ final TextView textView = (TextView) (convertView == null ? getDivider() : convertView);
+ setDividerPadding(textView, position == 0);
+ return textView;
+ }
+
+ ContactTileRow contactTileRowView = (ContactTileRow) convertView;
+ ArrayList<ContactEntry> contactList = getItem(position);
+
+ if (contactTileRowView == null) {
+ // Creating new row if needed
+ contactTileRowView = new ContactTileRow(mContext, itemViewType);
+ }
+
+ contactTileRowView.configureRow(contactList, position == getCount() - 1);
+ return contactTileRowView;
+ }
+
+ /**
+ * Divider uses a list_seperator.xml along with text to denote
+ * the most frequently contacted contacts.
+ */
+ private TextView getDivider() {
+ return MoreContactUtils.createHeaderView(mContext, R.string.favoritesFrequentContacted);
+ }
+
+ private void setDividerPadding(TextView headerTextView, boolean isFirstRow) {
+ MoreContactUtils.setHeaderViewBottomPadding(mContext, headerTextView, isFirstRow);
+ }
+
+ private int getLayoutResourceId(int viewType) {
+ switch (viewType) {
+ case ViewTypes.STARRED:
+ return mIsQuickContactEnabled ?
+ R.layout.contact_tile_starred_quick_contact : R.layout.contact_tile_starred;
+ case ViewTypes.FREQUENT:
+ return R.layout.contact_tile_frequent;
+ default:
+ throw new IllegalArgumentException("Unrecognized viewType " + viewType);
+ }
+ }
+ @Override
+ public int getViewTypeCount() {
+ return ViewTypes.COUNT;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ /*
+ * Returns view type based on {@link DisplayType}.
+ * {@link DisplayType#STARRED_ONLY} and {@link DisplayType#GROUP_MEMBERS}
+ * are {@link ViewTypes#STARRED}.
+ * {@link DisplayType#FREQUENT_ONLY} is {@link ViewTypes#FREQUENT}.
+ * {@link DisplayType#STREQUENT} mixes both {@link ViewTypes}
+ * and also adds in {@link ViewTypes#DIVIDER}.
+ */
+ switch (mDisplayType) {
+ case STREQUENT:
+ if (position < getRowCount(mDividerPosition)) {
+ return ViewTypes.STARRED;
+ } else if (position == getRowCount(mDividerPosition)) {
+ return ViewTypes.DIVIDER;
+ } else {
+ return ViewTypes.FREQUENT;
+ }
+ case STARRED_ONLY:
+ return ViewTypes.STARRED;
+ case FREQUENT_ONLY:
+ return ViewTypes.FREQUENT;
+ default:
+ throw new IllegalStateException("Unrecognized DisplayType " + mDisplayType);
+ }
+ }
+
+ /**
+ * Returns the "frequent header" position. Only available when STREQUENT or
+ * STREQUENT_PHONE_ONLY is used for its display type.
+ */
+ public int getFrequentHeaderPosition() {
+ return getRowCount(mDividerPosition);
+ }
+
+ /**
+ * Acts as a row item composed of {@link ContactTileView}
+ *
+ * TODO: FREQUENT doesn't really need it. Just let {@link #getView} return
+ */
+ private class ContactTileRow extends FrameLayout {
+ private int mItemViewType;
+ private int mLayoutResId;
+
+ public ContactTileRow(Context context, int itemViewType) {
+ super(context);
+ mItemViewType = itemViewType;
+ mLayoutResId = getLayoutResourceId(mItemViewType);
+
+ // Remove row (but not children) from accessibility node tree.
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ }
+
+ /**
+ * Configures the row to add {@link ContactEntry}s information to the views
+ */
+ public void configureRow(ArrayList<ContactEntry> list, boolean isLastRow) {
+ int columnCount = mItemViewType == ViewTypes.FREQUENT ? 1 : mColumnCount;
+
+ // Adding tiles to row and filling in contact information
+ for (int columnCounter = 0; columnCounter < columnCount; columnCounter++) {
+ ContactEntry entry =
+ columnCounter < list.size() ? list.get(columnCounter) : null;
+ addTileFromEntry(entry, columnCounter, isLastRow);
+ }
+ }
+
+ private void addTileFromEntry(ContactEntry entry, int childIndex, boolean isLastRow) {
+ final ContactTileView contactTile;
+
+ if (getChildCount() <= childIndex) {
+ contactTile = (ContactTileView) inflate(mContext, mLayoutResId, null);
+ // Note: the layoutparam set here is only actually used for FREQUENT.
+ // We override onMeasure() for STARRED and we don't care the layout param there.
+ Resources resources = mContext.getResources();
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ params.setMargins(
+ mWhitespaceStartEnd,
+ 0,
+ mWhitespaceStartEnd,
+ 0);
+ contactTile.setLayoutParams(params);
+ contactTile.setPhotoManager(mPhotoManager);
+ contactTile.setListener(mListener);
+ addView(contactTile);
+ } else {
+ contactTile = (ContactTileView) getChildAt(childIndex);
+ }
+ contactTile.loadFromContact(entry);
+
+ switch (mItemViewType) {
+ case ViewTypes.STARRED:
+ // Set padding between tiles. Divide mPaddingInPixels between left and right
+ // tiles as evenly as possible.
+ contactTile.setPaddingRelative(
+ (mPaddingInPixels + 1) / 2, 0,
+ mPaddingInPixels
+ / 2, 0);
+ break;
+ case ViewTypes.FREQUENT:
+ contactTile.setHorizontalDividerVisibility(
+ isLastRow ? View.GONE : View.VISIBLE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ switch (mItemViewType) {
+ case ViewTypes.STARRED:
+ onLayoutForTiles();
+ return;
+ default:
+ super.onLayout(changed, left, top, right, bottom);
+ return;
+ }
+ }
+
+ private void onLayoutForTiles() {
+ final int count = getChildCount();
+
+ // Amount of margin needed on the left is based on difference between offset and padding
+ int childLeft = mWhitespaceStartEnd - (mPaddingInPixels + 1) / 2;
+
+ // Just line up children horizontally.
+ for (int i = 0; i < count; i++) {
+ final int rtlAdjustedIndex = ViewUtil.isViewLayoutRtl(this) ? count - i - 1 : i;
+ final View child = getChildAt(rtlAdjustedIndex);
+
+ // Note MeasuredWidth includes the padding.
+ final int childWidth = child.getMeasuredWidth();
+ child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
+ childLeft += childWidth;
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ switch (mItemViewType) {
+ case ViewTypes.STARRED:
+ onMeasureForTiles(widthMeasureSpec);
+ return;
+ default:
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ return;
+ }
+ }
+
+ private void onMeasureForTiles(int widthMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ // Just in case...
+ setMeasuredDimension(width, 0);
+ return;
+ }
+
+ // 1. Calculate image size.
+ // = ([total width] - [total whitespace]) / [child count]
+ //
+ // 2. Set it to width/height of each children.
+ // If we have a remainder, some tiles will have 1 pixel larger width than its height.
+ //
+ // 3. Set the dimensions of itself.
+ // Let width = given width.
+ // Let height = wrap content.
+
+ final int totalWhitespaceInPixels = (mColumnCount - 1) * mPaddingInPixels
+ + mWhitespaceStartEnd * 2;
+
+ // Preferred width / height for images (excluding the padding).
+ // The actual width may be 1 pixel larger than this if we have a remainder.
+ final int imageSize = (width - totalWhitespaceInPixels) / mColumnCount;
+ final int remainder = width - (imageSize * mColumnCount) - totalWhitespaceInPixels;
+
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ final int childWidth = imageSize + child.getPaddingRight() + child.getPaddingLeft()
+ // Compensate for the remainder
+ + (i < remainder ? 1 : 0);
+
+ child.measure(
+ MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
+ );
+ }
+ setMeasuredDimension(width, getChildAt(0).getMeasuredHeight());
+ }
+ }
+
+ protected static class ViewTypes {
+ public static final int COUNT = 4;
+ public static final int STARRED = 0;
+ public static final int DIVIDER = 1;
+ public static final int FREQUENT = 2;
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactTileFrequentView.java b/src/com/android/contacts/common/list/ContactTileFrequentView.java
new file mode 100644
index 0000000..7dcd0a1
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactTileFrequentView.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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.common.list;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.contacts.common.util.ViewUtil;
+
+/**
+ * A {@link com.android.contacts.common.list.ContactTileView} that is used for most frequently contacted in the People app
+ */
+public class ContactTileFrequentView extends ContactTileView {
+ public ContactTileFrequentView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected boolean isDarkTheme() {
+ return false;
+ }
+
+ @Override
+ protected int getApproximateImageSize() {
+ return ViewUtil.getConstantPreLayoutWidth(getPhotoView());
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactTilePhoneFrequentView.java b/src/com/android/contacts/common/list/ContactTilePhoneFrequentView.java
new file mode 100644
index 0000000..aec93ab
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactTilePhoneFrequentView.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011 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.common.list;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.util.ViewUtil;
+
+/**
+ * A dark version of the {@link com.android.contacts.common.list.ContactTileView} that is used in Dialtacts
+ * for frequently called contacts. Slightly different behavior from superclass...
+ * when you tap it, you want to call the frequently-called number for the
+ * contact, even if that is not the default number for that contact.
+ */
+public class ContactTilePhoneFrequentView extends ContactTileView {
+ private String mPhoneNumberString;
+
+ public ContactTilePhoneFrequentView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected boolean isDarkTheme() {
+ return true;
+ }
+
+ @Override
+ protected int getApproximateImageSize() {
+ return ViewUtil.getConstantPreLayoutWidth(getQuickContact());
+ }
+
+ @Override
+ public void loadFromContact(ContactEntry entry) {
+ super.loadFromContact(entry);
+ mPhoneNumberString = null; // ... in case we're reusing the view
+ if (entry != null) {
+ // Grab the phone-number to call directly... see {@link onClick()}
+ mPhoneNumberString = entry.phoneNumber;
+ }
+ }
+
+ @Override
+ protected OnClickListener createClickListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mListener == null) return;
+ if (TextUtils.isEmpty(mPhoneNumberString)) {
+ // Copy "superclass" implementation
+ mListener.onContactSelected(getLookupUri(), MoreContactUtils
+ .getTargetRectFromView(ContactTilePhoneFrequentView.this));
+ } else {
+ // When you tap a frequently-called contact, you want to
+ // call them at the number that you usually talk to them
+ // at (i.e. the one displayed in the UI), regardless of
+ // whether that's their default number.
+ mListener.onCallNumberDirectly(mPhoneNumberString);
+ }
+ }
+ };
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactTileStarredView.java b/src/com/android/contacts/common/list/ContactTileStarredView.java
new file mode 100644
index 0000000..59ef81e
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactTileStarredView.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 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.common.list;
+
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * A {@link ContactTileStarredView} displays the contact's picture overlayed with their name
+ * in a square. The actual dimensions are set by
+ * {@link com.android.contacts.common.list.ContactTileAdapter.ContactTileRow}.
+ */
+public class ContactTileStarredView extends ContactTileView {
+
+ /**
+ * The photo manager should display the default image/letter at 80% of its normal size.
+ */
+ private static final float DEFAULT_IMAGE_LETTER_SCALE = 0.8f;
+
+ public ContactTileStarredView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected boolean isDarkTheme() {
+ return false;
+ }
+
+ @Override
+ protected int getApproximateImageSize() {
+ // The picture is the full size of the tile (minus some padding, but we can be generous)
+ return mListener.getApproximateTileWidth();
+ }
+
+ @Override
+ protected DefaultImageRequest getDefaultImageRequest(String displayName, String lookupKey) {
+ return new DefaultImageRequest(displayName, lookupKey, ContactPhotoManager.TYPE_DEFAULT,
+ DEFAULT_IMAGE_LETTER_SCALE, /* offset = */ 0, /* isCircular = */ true);
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactTileView.java b/src/com/android/contacts/common/list/ContactTileView.java
new file mode 100644
index 0000000..172d720
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactTileView.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2011 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.common.list;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.QuickContactBadge;
+import android.widget.TextView;
+
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.R;
+
+/**
+ * A ContactTile displays a contact's picture and name
+ */
+public abstract class ContactTileView extends FrameLayout {
+ private final static String TAG = ContactTileView.class.getSimpleName();
+
+ private Uri mLookupUri;
+ private ImageView mPhoto;
+ private QuickContactBadge mQuickContact;
+ private TextView mName;
+ private TextView mStatus;
+ private TextView mPhoneLabel;
+ private TextView mPhoneNumber;
+ private ContactPhotoManager mPhotoManager = null;
+ private View mPushState;
+ private View mHorizontalDivider;
+ protected Listener mListener;
+
+ public ContactTileView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mName = (TextView) findViewById(R.id.contact_tile_name);
+
+ mQuickContact = (QuickContactBadge) findViewById(R.id.contact_tile_quick);
+ mPhoto = (ImageView) findViewById(R.id.contact_tile_image);
+ mStatus = (TextView) findViewById(R.id.contact_tile_status);
+ mPhoneLabel = (TextView) findViewById(R.id.contact_tile_phone_type);
+ mPhoneNumber = (TextView) findViewById(R.id.contact_tile_phone_number);
+ mPushState = findViewById(R.id.contact_tile_push_state);
+ mHorizontalDivider = findViewById(R.id.contact_tile_horizontal_divider);
+
+ OnClickListener listener = createClickListener();
+ setOnClickListener(listener);
+ }
+
+ protected OnClickListener createClickListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mListener == null) return;
+ mListener.onContactSelected(
+ getLookupUri(),
+ MoreContactUtils.getTargetRectFromView(ContactTileView.this));
+ }
+ };
+ }
+
+ public void setPhotoManager(ContactPhotoManager photoManager) {
+ mPhotoManager = photoManager;
+ }
+
+ /**
+ * Populates the data members to be displayed from the
+ * fields in {@link com.android.contacts.common.list.ContactEntry}
+ */
+ public void loadFromContact(ContactEntry entry) {
+
+ if (entry != null) {
+ mName.setText(getNameForView(entry));
+ mLookupUri = entry.lookupUri;
+
+ if (mStatus != null) {
+ if (entry.status == null) {
+ mStatus.setVisibility(View.GONE);
+ } else {
+ mStatus.setText(entry.status);
+ mStatus.setCompoundDrawablesWithIntrinsicBounds(entry.presenceIcon,
+ null, null, null);
+ mStatus.setVisibility(View.VISIBLE);
+ }
+ }
+
+ if (mPhoneLabel != null) {
+ if (TextUtils.isEmpty(entry.phoneLabel)) {
+ mPhoneLabel.setVisibility(View.GONE);
+ } else {
+ mPhoneLabel.setVisibility(View.VISIBLE);
+ mPhoneLabel.setText(entry.phoneLabel);
+ }
+ }
+
+ if (mPhoneNumber != null) {
+ // TODO: Format number correctly
+ mPhoneNumber.setText(entry.phoneNumber);
+ }
+
+ setVisibility(View.VISIBLE);
+
+ if (mPhotoManager != null) {
+ DefaultImageRequest request = getDefaultImageRequest(entry.namePrimary,
+ entry.lookupKey);
+ configureViewForImage(entry.photoUri == null);
+ if (mPhoto != null) {
+ mPhotoManager.loadPhoto(mPhoto, entry.photoUri, getApproximateImageSize(),
+ isDarkTheme(), isContactPhotoCircular(), request);
+
+ if (mQuickContact != null) {
+ mQuickContact.assignContactUri(mLookupUri);
+ }
+ } else if (mQuickContact != null) {
+ mQuickContact.assignContactUri(mLookupUri);
+ mPhotoManager.loadPhoto(mQuickContact, entry.photoUri,
+ getApproximateImageSize(), isDarkTheme(), isContactPhotoCircular(),
+ request);
+ }
+ } else {
+ Log.w(TAG, "contactPhotoManager not set");
+ }
+
+ if (mPushState != null) {
+ mPushState.setContentDescription(entry.namePrimary);
+ } else if (mQuickContact != null) {
+ mQuickContact.setContentDescription(entry.namePrimary);
+ }
+ } else {
+ setVisibility(View.INVISIBLE);
+ }
+ }
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ public void setHorizontalDividerVisibility(int visibility) {
+ if (mHorizontalDivider != null) mHorizontalDivider.setVisibility(visibility);
+ }
+
+ public Uri getLookupUri() {
+ return mLookupUri;
+ }
+
+ protected QuickContactBadge getQuickContact() {
+ return mQuickContact;
+ }
+
+ protected View getPhotoView() {
+ return mPhoto;
+ }
+
+ /**
+ * Returns the string that should actually be displayed as the contact's name. Subclasses
+ * can override this to return formatted versions of the name - i.e. first name only.
+ */
+ protected String getNameForView(ContactEntry contactEntry) {
+ return contactEntry.namePrimary;
+ }
+
+ /**
+ * Implemented by subclasses to estimate the size of the picture. This can return -1 if only
+ * a thumbnail is shown anyway
+ */
+ protected abstract int getApproximateImageSize();
+
+ protected abstract boolean isDarkTheme();
+
+ /**
+ * Implemented by subclasses to reconfigure the view's layout and subviews, based on whether
+ * or not the contact has a user-defined photo.
+ *
+ * @param isDefaultImage True if the contact does not have a user-defined contact photo
+ * (which means a default contact image will be applied by the {@link ContactPhotoManager}
+ */
+ protected void configureViewForImage(boolean isDefaultImage) {
+ // No-op by default.
+ }
+
+ /**
+ * Implemented by subclasses to allow them to return a {@link DefaultImageRequest} with the
+ * various image parameters defined to match their own layouts.
+ *
+ * @param displayName The display name of the contact
+ * @param lookupKey The lookup key of the contact
+ * @return A {@link DefaultImageRequest} object with each field configured by the subclass
+ * as desired, or {@code null}.
+ */
+ protected DefaultImageRequest getDefaultImageRequest(String displayName, String lookupKey) {
+ return new DefaultImageRequest(displayName, lookupKey, isContactPhotoCircular());
+ }
+
+ /**
+ * Whether contact photo should be displayed as a circular image. Implemented by subclasses
+ * so they can change which drawables to fetch.
+ */
+ protected boolean isContactPhotoCircular() {
+ return true;
+ }
+
+ public interface Listener {
+ /**
+ * Notification that the contact was selected; no specific action is dictated.
+ */
+ void onContactSelected(Uri contactLookupUri, Rect viewRect);
+ /**
+ * Notification that the specified number is to be called.
+ */
+ void onCallNumberDirectly(String phoneNumber);
+ /**
+ * @return The width of each tile. This doesn't have to be a precise number (e.g. paddings
+ * can be ignored), but is used to load the correct picture size from the database
+ */
+ int getApproximateTileWidth();
+ }
+}
diff --git a/src/com/android/contacts/common/list/ContactsSectionIndexer.java b/src/com/android/contacts/common/list/ContactsSectionIndexer.java
new file mode 100644
index 0000000..db64010
--- /dev/null
+++ b/src/com/android/contacts/common/list/ContactsSectionIndexer.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.text.TextUtils;
+import android.widget.SectionIndexer;
+
+import java.util.Arrays;
+
+/**
+ * A section indexer that is configured with precomputed section titles and
+ * their respective counts.
+ */
+public class ContactsSectionIndexer implements SectionIndexer {
+
+ protected static final String BLANK_HEADER_STRING = "\u2026"; // ellipsis
+
+ private String[] mSections;
+ private int[] mPositions;
+ private int mCount;
+
+ /**
+ * Constructor.
+ *
+ * @param sections a non-null array
+ * @param counts a non-null array of the same size as <code>sections</code>
+ */
+ public ContactsSectionIndexer(String[] sections, int[] counts) {
+ if (sections == null || counts == null) {
+ throw new NullPointerException();
+ }
+
+ if (sections.length != counts.length) {
+ throw new IllegalArgumentException(
+ "The sections and counts arrays must have the same length");
+ }
+
+ // TODO process sections/counts based on current locale and/or specific section titles
+
+ this.mSections = sections;
+ mPositions = new int[counts.length];
+ int position = 0;
+ for (int i = 0; i < counts.length; i++) {
+ if (TextUtils.isEmpty(mSections[i])) {
+ mSections[i] = BLANK_HEADER_STRING;
+ } else if (!mSections[i].equals(BLANK_HEADER_STRING)) {
+ mSections[i] = mSections[i].trim();
+ }
+
+ mPositions[i] = position;
+ position += counts[i];
+ }
+ mCount = position;
+ }
+
+ public Object[] getSections() {
+ return mSections;
+ }
+
+ public int[] getPositions() {
+ return mPositions;
+ }
+
+ public int getPositionForSection(int section) {
+ if (section < 0 || section >= mSections.length) {
+ return -1;
+ }
+
+ return mPositions[section];
+ }
+
+ public int getSectionForPosition(int position) {
+ if (position < 0 || position >= mCount) {
+ return -1;
+ }
+
+ int index = Arrays.binarySearch(mPositions, position);
+
+ /*
+ * Consider this example: section positions are 0, 3, 5; the supplied
+ * position is 4. The section corresponding to position 4 starts at
+ * position 3, so the expected return value is 1. Binary search will not
+ * find 4 in the array and thus will return -insertPosition-1, i.e. -3.
+ * To get from that number to the expected value of 1 we need to negate
+ * and subtract 2.
+ */
+ return index >= 0 ? index : -index - 2;
+ }
+
+ public void setProfileAndFavoritesHeader(String header, int numberOfItemsToAdd) {
+ if (mSections != null) {
+ // Don't do anything if the header is already set properly.
+ if (mSections.length > 0 && header.equals(mSections[0])) {
+ return;
+ }
+
+ // Since the section indexer isn't aware of the profile at the top, we need to add a
+ // special section at the top for it and shift everything else down.
+ String[] tempSections = new String[mSections.length + 1];
+ int[] tempPositions = new int[mPositions.length + 1];
+ tempSections[0] = header;
+ tempPositions[0] = 0;
+ for (int i = 1; i <= mPositions.length; i++) {
+ tempSections[i] = mSections[i - 1];
+ tempPositions[i] = mPositions[i - 1] + numberOfItemsToAdd;
+ }
+ mSections = tempSections;
+ mPositions = tempPositions;
+ mCount = mCount + numberOfItemsToAdd;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/list/CustomContactListFilterActivity.java b/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
new file mode 100644
index 0000000..04337b8
--- /dev/null
+++ b/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
@@ -0,0 +1,948 @@
+/*
+ * 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.common.list;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.app.ProgressDialog;
+import android.content.AsyncTaskLoader;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.Loader;
+import android.content.OperationApplicationException;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+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.Menu;
+import android.view.MenuItem;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.CheckBox;
+import android.widget.ExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
+import android.widget.TextView;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.util.EmptyService;
+import com.android.contacts.common.util.LocalizedNameResolver;
+import com.android.contacts.common.util.WeakAsyncTask;
+import com.google.common.collect.Lists;
+
+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 class CustomContactListFilterActivity extends Activity implements
+ ExpandableListView.OnChildClickListener,
+ LoaderCallbacks<CustomContactListFilterActivity.AccountSet> {
+ private static final String TAG = "CustomContactListFilterActivity";
+
+ private static final int ACCOUNT_SET_LOADER_ID = 1;
+
+ private ExpandableListView mList;
+ private DisplayAdapter mAdapter;
+
+ private SharedPreferences mPrefs;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.contact_list_filter_custom);
+
+ mList = (ExpandableListView) findViewById(android.R.id.list);
+ mList.setOnChildClickListener(this);
+ mList.setHeaderDividersEnabled(true);
+ mList.setChildDivider(new ColorDrawable(Color.TRANSPARENT));
+
+ mList.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(final View v, final int left, final int top, final int right,
+ final int bottom, final int oldLeft, final int oldTop, final int oldRight,
+ final int oldBottom) {
+ mList.setIndicatorBounds(
+ mList.getWidth() - getResources().getDimensionPixelSize(
+ R.dimen.contact_filter_indicator_padding_end),
+ mList.getWidth() - getResources().getDimensionPixelSize(
+ R.dimen.contact_filter_indicator_padding_start));
+ }
+ });
+
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ mAdapter = new DisplayAdapter(this);
+
+ mList.setOnCreateContextMenuListener(this);
+
+ mList.setAdapter(mAdapter);
+
+ ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ // android.R.id.home will be triggered in onOptionsItemSelected()
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
+ }
+
+ public static class CustomFilterConfigurationLoader extends AsyncTaskLoader<AccountSet> {
+
+ private AccountSet mAccountSet;
+
+ public CustomFilterConfigurationLoader(Context context) {
+ super(context);
+ }
+
+ @Override
+ public AccountSet loadInBackground() {
+ Context context = getContext();
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
+ final ContentResolver resolver = context.getContentResolver();
+
+ final AccountSet accounts = new AccountSet();
+ for (AccountWithDataSet account : accountTypes.getAccounts(false)) {
+ final AccountType accountType = accountTypes.getAccountTypeForAccount(account);
+ if (accountType.isExtension() && !account.hasData(context)) {
+ // Extension with no data -- skip.
+ continue;
+ }
+
+ AccountDisplay accountDisplay =
+ new AccountDisplay(resolver, account.name, account.type, account.dataSet);
+
+ final Uri.Builder groupsUri = Groups.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Groups.ACCOUNT_NAME, account.name)
+ .appendQueryParameter(Groups.ACCOUNT_TYPE, account.type);
+ if (account.dataSet != null) {
+ groupsUri.appendQueryParameter(Groups.DATA_SET, account.dataSet).build();
+ }
+ final Cursor cursor = resolver.query(groupsUri.build(), null, null, null, null);
+ if (cursor == null) {
+ continue;
+ }
+ android.content.EntityIterator iterator =
+ ContactsContract.Groups.newEntityIterator(cursor);
+ try {
+ boolean hasGroups = false;
+
+ // Create entries for each known group
+ while (iterator.hasNext()) {
+ final ContentValues values = iterator.next().getEntityValues();
+ final GroupDelta group = GroupDelta.fromBefore(values);
+ accountDisplay.addGroup(group);
+ hasGroups = true;
+ }
+ // Create single entry handling ungrouped status
+ accountDisplay.mUngrouped =
+ GroupDelta.fromSettings(resolver, account.name, account.type,
+ account.dataSet, hasGroups);
+ accountDisplay.addGroup(accountDisplay.mUngrouped);
+ } finally {
+ iterator.close();
+ }
+
+ accounts.add(accountDisplay);
+ }
+
+ return accounts;
+ }
+
+ @Override
+ public void deliverResult(AccountSet cursor) {
+ if (isReset()) {
+ return;
+ }
+
+ mAccountSet = cursor;
+
+ if (isStarted()) {
+ super.deliverResult(cursor);
+ }
+ }
+
+ @Override
+ protected void onStartLoading() {
+ if (mAccountSet != null) {
+ deliverResult(mAccountSet);
+ }
+ if (takeContentChanged() || mAccountSet == null) {
+ forceLoad();
+ }
+ }
+
+ @Override
+ protected void onStopLoading() {
+ cancelLoad();
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+ onStopLoading();
+ mAccountSet = null;
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ getLoaderManager().initLoader(ACCOUNT_SET_LOADER_ID, null, this);
+ super.onStart();
+ }
+
+ @Override
+ public Loader<AccountSet> onCreateLoader(int id, Bundle args) {
+ return new CustomFilterConfigurationLoader(this);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<AccountSet> loader, AccountSet data) {
+ mAdapter.setAccounts(data);
+ }
+
+ @Override
+ public void onLoaderReset(Loader<AccountSet> loader) {
+ mAdapter.setAccounts(null);
+ }
+
+ 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}, {@link Settings#ACCOUNT_TYPE}, and
+ * {@link Settings#DATA_SET}.
+ */
+ public static GroupDelta fromSettings(ContentResolver resolver, String accountName,
+ String accountType, String dataSet, boolean accountHasGroups) {
+ final Uri.Builder settingsUri = Settings.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Settings.ACCOUNT_NAME, accountName)
+ .appendQueryParameter(Settings.ACCOUNT_TYPE, accountType);
+ if (dataSet != null) {
+ settingsUri.appendQueryParameter(Settings.DATA_SET, dataSet);
+ }
+ final Cursor cursor = resolver.query(settingsUri.build(), 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);
+ values.put(Settings.DATA_SET, dataSet);
+
+ 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);
+ }
+
+ private String getAccountType() {
+ return (mBefore == null ? mAfter : mBefore).getAsString(Settings.ACCOUNT_TYPE);
+ }
+
+ public CharSequence getTitle(Context context) {
+ if (mUngrouped) {
+ final String customAllContactsName =
+ LocalizedNameResolver.getAllContactsName(context, getAccountType());
+ if (customAllContactsName != null) {
+ return customAllContactsName;
+ }
+ 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 (isInsert()) {
+ // Only allow inserts for Settings
+ if (mUngrouped) {
+ mAfter.remove(mIdColumn);
+ return ContentProviderOperation.newInsert(Settings.CONTENT_URI)
+ .withValues(mAfter)
+ .build();
+ }
+ else {
+ throw new IllegalStateException("Unexpected diff");
+ }
+ } else if (isUpdate()) {
+ if (mUngrouped) {
+ String accountName = this.getAsString(Settings.ACCOUNT_NAME);
+ String accountType = this.getAsString(Settings.ACCOUNT_TYPE);
+ String dataSet = this.getAsString(Settings.DATA_SET);
+ StringBuilder selection = new StringBuilder(Settings.ACCOUNT_NAME + "=? AND "
+ + Settings.ACCOUNT_TYPE + "=?");
+ String[] selectionArgs;
+ if (dataSet == null) {
+ selection.append(" AND " + Settings.DATA_SET + " IS NULL");
+ selectionArgs = new String[] {accountName, accountType};
+ } else {
+ selection.append(" AND " + Settings.DATA_SET + "=?");
+ selectionArgs = new String[] {accountName, accountType, dataSet};
+ }
+ return ContentProviderOperation.newUpdate(Settings.CONTENT_URI)
+ .withSelection(selection.toString(), selectionArgs)
+ .withValues(mAfter)
+ .build();
+ } else {
+ return ContentProviderOperation.newUpdate(
+ addCallerIsSyncAdapterParameter(Groups.CONTENT_URI))
+ .withSelection(Groups._ID + "=" + this.getId(), null)
+ .withValues(mAfter)
+ .build();
+ }
+ } else {
+ return null;
+ }
+ }
+ }
+
+ 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) {
+ final Long id1 = object1.getId();
+ final Long id2 = object2.getId();
+ if (id1 == null && id2 == null) {
+ return 0;
+ } else if (id1 == null) {
+ return -1;
+ } else if (id2 == null) {
+ return 1;
+ } else if (id1 < id2) {
+ return -1;
+ } else if (id1 > id2) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ };
+
+ /**
+ * 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 AccountWithDataSet}, usually shown as
+ * children under a single expandable group.
+ */
+ protected static class AccountDisplay {
+ public final String mName;
+ public final String mType;
+ public final String mDataSet;
+
+ 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 AccountWithDataSet}.
+ */
+ public AccountDisplay(ContentResolver resolver, String accountName, String accountType,
+ String dataSet) {
+ mName = accountName;
+ mType = accountType;
+ mDataSet = dataSet;
+ }
+
+ /**
+ * 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 AccountWithDataSet}.
+ */
+ 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 AccountWithDataSet} type. 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 AccountTypeManager mAccountTypes;
+ private AccountSet mAccounts;
+
+ private boolean mChildWithPhones = false;
+
+ public DisplayAdapter(Context context) {
+ mContext = context;
+ mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mAccountTypes = AccountTypeManager.getInstance(context);
+ }
+
+ public void setAccounts(AccountSet accounts) {
+ mAccounts = accounts;
+ notifyDataSetChanged();
+ }
+
+ /**
+ * In group descriptions, show the number of contacts with phone
+ * numbers, in addition to the total contacts.
+ */
+ public void setChildDescripWithPhones(boolean withPhones) {
+ mChildWithPhones = withPhones;
+ }
+
+ @Override
+ public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+ ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(
+ R.layout.custom_contact_list_filter_account, 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 AccountType accountType = mAccountTypes.getAccountType(
+ account.mType, account.mDataSet);
+
+ text1.setText(account.mName);
+ text1.setVisibility(account.mName == null ? View.GONE : View.VISIBLE);
+ text2.setText(accountType.getDisplayLabel(mContext));
+
+ final int textColor = mContext.getResources().getColor(isExpanded
+ ? R.color.dialtacts_theme_color
+ : R.color.account_filter_text_color);
+ text1.setTextColor(textColor);
+ text2.setTextColor(textColor);
+
+ return convertView;
+ }
+
+ @Override
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+ View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(
+ R.layout.custom_contact_list_filter_group, 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);
+ 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);
+ }
+
+ // Show divider at bottom only for the last child.
+ final View dividerBottom = convertView.findViewById(R.id.adapter_divider_bottom);
+ dividerBottom.setVisibility(isLastChild ? View.VISIBLE : View.GONE);
+
+ return convertView;
+ }
+
+ @Override
+ 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;
+ }
+ }
+
+ @Override
+ 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;
+ }
+ }
+
+ @Override
+ 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);
+ }
+
+ @Override
+ public Object getGroup(int groupPosition) {
+ return mAccounts.get(groupPosition);
+ }
+
+ @Override
+ public int getGroupCount() {
+ if (mAccounts == null) {
+ return 0;
+ }
+ return mAccounts.size();
+ }
+
+ @Override
+ public long getGroupId(int groupPosition) {
+ return groupPosition;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ @Override
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
+ }
+ }
+
+ /**
+ * 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 (GoogleAccountType.ACCOUNT_TYPE.equals(account.mType) && account.mDataSet == null) {
+ 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;
+ }
+ });
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void doSaveAction() {
+ if (mAdapter == null || mAdapter.mAccounts == null) {
+ finish();
+ return;
+ }
+
+ setResult(RESULT_OK);
+
+ final ArrayList<ContentProviderOperation> diff = mAdapter.mAccounts.buildDiff();
+ if (diff.isEmpty()) {
+ finish();
+ return;
+ }
+
+ new UpdateTask(this).execute(diff);
+ }
+
+ /**
+ * Background task that persists changes to {@link Groups#GROUP_VISIBLE},
+ * showing spinner dialog to user while updating.
+ */
+ public static class UpdateTask extends
+ WeakAsyncTask<ArrayList<ContentProviderOperation>, Void, Void, Activity> {
+ private ProgressDialog mProgress;
+
+ public UpdateTask(Activity target) {
+ super(target);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onPreExecute(Activity target) {
+ final Context context = target;
+
+ mProgress = 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, ArrayList<ContentProviderOperation>... params) {
+ final Context context = target;
+ final ContentValues values = new ContentValues();
+ final ContentResolver resolver = context.getContentResolver();
+
+ try {
+ final ArrayList<ContentProviderOperation> diff = params[0];
+ 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;
+
+ try {
+ mProgress.dismiss();
+ } catch (Exception e) {
+ Log.e(TAG, "Error dismissing progress dialog", e);
+ }
+
+ target.finish();
+
+ // Stop the service that was protecting us
+ context.stopService(new Intent(context, EmptyService.class));
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+
+ final MenuItem menuItem = menu.add(Menu.NONE, R.id.menu_save, Menu.NONE,
+ R.string.menu_custom_filter_save);
+ menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ // Pretend cancel.
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ return true;
+ case R.id.menu_save:
+ this.doSaveAction();
+ return true;
+ default:
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/src/com/android/contacts/common/list/DefaultContactListAdapter.java b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
new file mode 100644
index 0000000..666de8c
--- /dev/null
+++ b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.net.Uri;
+import android.net.Uri.Builder;
+import android.preference.PreferenceManager;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.SearchSnippets;
+import android.text.TextUtils;
+import android.view.View;
+
+import com.android.contacts.common.compat.ContactsCompat;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.preference.ContactsPreferences;
+import com.android.contactsbind.experiments.Flags;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type.
+ */
+public class DefaultContactListAdapter extends ContactListAdapter {
+
+ public static final char SNIPPET_START_MATCH = '[';
+ public static final char SNIPPET_END_MATCH = ']';
+
+ // Contacts contacted within the last 3 days (in seconds)
+ private static final long LAST_TIME_USED_3_DAYS_SEC = 3L * 24 * 60 * 60;
+
+ // Contacts contacted within the last 7 days (in seconds)
+ private static final long LAST_TIME_USED_7_DAYS_SEC = 7L * 24 * 60 * 60;
+
+ // Contacts contacted within the last 14 days (in seconds)
+ private static final long LAST_TIME_USED_14_DAYS_SEC = 14L * 24 * 60 * 60;
+
+ // Contacts contacted within the last 30 days (in seconds)
+ private static final long LAST_TIME_USED_30_DAYS_SEC = 30L * 24 * 60 * 60;
+
+ private static final String TIME_SINCE_LAST_USED_SEC =
+ "(strftime('%s', 'now') - " + Contacts.LAST_TIME_CONTACTED + "/1000)";
+
+ private static final String STREQUENT_SORT =
+ "(CASE WHEN " + TIME_SINCE_LAST_USED_SEC + " < " + LAST_TIME_USED_3_DAYS_SEC +
+ " THEN 0 " +
+ " WHEN " + TIME_SINCE_LAST_USED_SEC + " < " + LAST_TIME_USED_7_DAYS_SEC +
+ " THEN 1 " +
+ " WHEN " + TIME_SINCE_LAST_USED_SEC + " < " + LAST_TIME_USED_14_DAYS_SEC +
+ " THEN 2 " +
+ " WHEN " + TIME_SINCE_LAST_USED_SEC + " < " + LAST_TIME_USED_30_DAYS_SEC +
+ " THEN 3 " +
+ " ELSE 4 END), " +
+ Contacts.TIMES_CONTACTED + " DESC, " +
+ Contacts.STARRED + " DESC";
+
+ public DefaultContactListAdapter(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void configureLoader(CursorLoader loader, long directoryId) {
+ if (loader instanceof FavoritesAndContactsLoader) {
+ ((FavoritesAndContactsLoader) loader).setLoadFavorites(shouldIncludeFavorites());
+ }
+
+ String sortOrder = null;
+ if (isSearchMode()) {
+ String query = getQueryString();
+ if (query == null) query = "";
+ query = query.trim();
+ if (TextUtils.isEmpty(query)) {
+ // Regardless of the directory, we don't want anything returned,
+ // so let's just send a "nothing" query to the local directory.
+ loader.setUri(Contacts.CONTENT_URI);
+ loader.setProjection(getProjection(false));
+ loader.setSelection("0");
+ } else if (isGroupMembersFilter()) {
+ final ContactListFilter filter = getFilter();
+ configureUri(loader, directoryId, filter);
+ // TODO: This is not the normal type to filter URI so we load the non-search
+ // projection. Consider creating a specific group member adapter to make it more
+ // clear.
+ loader.setProjection(getProjection(/* forSearch */ false));
+ loader.setSelection(
+ Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?1 OR " +
+ Contacts.DISPLAY_NAME_ALTERNATIVE + " LIKE ?1");
+ final String[] args = new String[1];
+ args[0] = query + "%";
+ loader.setSelectionArgs(args);
+ } else {
+ final Builder builder = ContactsCompat.getContentUri().buildUpon();
+ appendSearchParameters(builder, query, directoryId);
+ loader.setUri(builder.build());
+ loader.setProjection(getProjection(true));
+ sortOrder = STREQUENT_SORT;
+ }
+ } else {
+ final ContactListFilter filter = getFilter();
+ configureUri(loader, directoryId, filter);
+ if (filter != null
+ && filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
+ loader.setProjection(getDataProjectionForContacts(false));
+ } else {
+ loader.setProjection(getProjection(false));
+ }
+ configureSelection(loader, directoryId, filter);
+ }
+
+ if (getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY) {
+ if (sortOrder == null) {
+ sortOrder = Contacts.SORT_KEY_PRIMARY;
+ } else {
+ sortOrder += ", " + Contacts.SORT_KEY_PRIMARY;
+ }
+ } else {
+ if (sortOrder == null) {
+ sortOrder = Contacts.SORT_KEY_ALTERNATIVE;
+ } else {
+ sortOrder += ", " + Contacts.SORT_KEY_ALTERNATIVE;
+ }
+ }
+ loader.setSortOrder(sortOrder);
+ }
+
+ private boolean isGroupMembersFilter() {
+ final ContactListFilter filter = getFilter();
+ return filter != null && filter.filterType == ContactListFilter.FILTER_TYPE_GROUP_MEMBERS;
+ }
+
+ private void appendSearchParameters(Builder builder, String query, long directoryId) {
+ builder.appendPath(query); // Builder will encode the query
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ if (directoryId != Directory.DEFAULT && directoryId != Directory.LOCAL_INVISIBLE) {
+ builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
+ }
+ builder.appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY, "1");
+ }
+
+ protected void configureUri(CursorLoader loader, long directoryId, ContactListFilter filter) {
+ Uri uri = Contacts.CONTENT_URI;
+ if (filter != null) {
+ if (filter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
+ String lookupKey = getSelectedContactLookupKey();
+ if (lookupKey != null) {
+ uri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey);
+ } else {
+ uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, getSelectedContactId());
+ }
+ } else if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
+ uri = Data.CONTENT_URI;
+ }
+ }
+
+ if (directoryId == Directory.DEFAULT && isSectionHeaderDisplayEnabled()) {
+ uri = ContactListAdapter.buildSectionIndexerUri(uri);
+ }
+
+ // The "All accounts" filter is the same as the entire contents of Directory.DEFAULT
+ if (filter != null
+ && filter.filterType != ContactListFilter.FILTER_TYPE_CUSTOM
+ && filter.filterType != ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
+ final Uri.Builder builder = uri.buildUpon();
+ builder.appendQueryParameter(
+ ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT));
+ if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT
+ || filter.filterType == ContactListFilter.FILTER_TYPE_GROUP_MEMBERS) {
+ filter.addAccountQueryParameterToUrl(builder);
+ }
+ uri = builder.build();
+ }
+
+ loader.setUri(uri);
+ }
+
+ private void configureSelection(
+ CursorLoader loader, long directoryId, ContactListFilter filter) {
+ if (filter == null) {
+ return;
+ }
+
+ if (directoryId != Directory.DEFAULT) {
+ return;
+ }
+
+ StringBuilder selection = new StringBuilder();
+ List<String> selectionArgs = new ArrayList<String>();
+
+ switch (filter.filterType) {
+ case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS: {
+ // We have already added directory=0 to the URI, which takes care of this
+ // filter
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_SINGLE_CONTACT: {
+ // We have already added the lookup key to the URI, which takes care of this
+ // filter
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_STARRED: {
+ selection.append(Contacts.STARRED + "!=0");
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY: {
+ selection.append(Contacts.HAS_PHONE_NUMBER + "=1");
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_CUSTOM: {
+ selection.append(Contacts.IN_VISIBLE_GROUP + "=1");
+ if (isCustomFilterForPhoneNumbersOnly()) {
+ selection.append(" AND " + Contacts.HAS_PHONE_NUMBER + "=1");
+ }
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_ACCOUNT: {
+ // We use query parameters for account filter, so no selection to add here.
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_GROUP_MEMBERS: {
+ // TODO(wjang): check if we need it
+ // selection.append(Contacts.IN_VISIBLE_GROUP + "=1");
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS: {
+ selection.append(AccountWithDataSet.LOCAL_ACCOUNT_SELECTION);
+ break;
+ }
+ }
+ loader.setSelection(selection.toString());
+ loader.setSelectionArgs(selectionArgs.toArray(new String[0]));
+ }
+
+ @Override
+ protected void bindView(View itemView, int partition, Cursor cursor, int position) {
+ super.bindView(itemView, partition, cursor, position);
+ final ContactListItemView view = (ContactListItemView)itemView;
+
+ view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);
+
+ if (isSelectionVisible()) {
+ view.setActivated(isSelectedContact(partition, cursor));
+ }
+
+ bindSectionHeaderAndDivider(view, position, cursor);
+
+ if (isQuickContactEnabled()) {
+ bindQuickContact(view, partition, cursor, ContactQuery.CONTACT_PHOTO_ID,
+ ContactQuery.CONTACT_PHOTO_URI, ContactQuery.CONTACT_ID,
+ ContactQuery.CONTACT_LOOKUP_KEY, ContactQuery.CONTACT_DISPLAY_NAME);
+ } else {
+ if (getDisplayPhotos()) {
+ bindPhoto(view, partition, cursor);
+ }
+ }
+
+ bindNameAndViewId(view, cursor);
+ bindPresenceAndStatusMessage(view, cursor);
+
+ if (isSearchMode()) {
+ bindSearchSnippet(view, cursor);
+ } else {
+ view.setSnippet(null);
+ }
+ }
+
+ private boolean isCustomFilterForPhoneNumbersOnly() {
+ // TODO: this flag should not be stored in shared prefs. It needs to be in the db.
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
+ return prefs.getBoolean(ContactsPreferences.PREF_DISPLAY_ONLY_PHONES,
+ ContactsPreferences.PREF_DISPLAY_ONLY_PHONES_DEFAULT);
+ }
+}
diff --git a/src/com/android/contacts/common/list/DirectoryListLoader.java b/src/com/android/contacts/common/list/DirectoryListLoader.java
new file mode 100644
index 0000000..c45a3ca
--- /dev/null
+++ b/src/com/android/contacts/common/list/DirectoryListLoader.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Directory;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.DirectoryCompat;
+
+/**
+ * A specialized loader for the list of directories, see {@link Directory}.
+ */
+public class DirectoryListLoader extends AsyncTaskLoader<Cursor> {
+
+ private static final String TAG = "ContactEntryListAdapter";
+
+ public static final int SEARCH_MODE_NONE = 0;
+ public static final int SEARCH_MODE_DEFAULT = 1;
+ public static final int SEARCH_MODE_CONTACT_SHORTCUT = 2;
+ public static final int SEARCH_MODE_DATA_SHORTCUT = 3;
+
+ private static final class DirectoryQuery {
+ public static final String ORDER_BY = Directory._ID;
+
+ public static final String[] PROJECTION = {
+ Directory._ID,
+ Directory.PACKAGE_NAME,
+ Directory.TYPE_RESOURCE_ID,
+ Directory.DISPLAY_NAME,
+ Directory.PHOTO_SUPPORT,
+ };
+
+ public static final int ID = 0;
+ public static final int PACKAGE_NAME = 1;
+ public static final int TYPE_RESOURCE_ID = 2;
+ public static final int DISPLAY_NAME = 3;
+ public static final int PHOTO_SUPPORT = 4;
+
+ public static Uri getDirectoryUri(int mode) {
+ if (mode == SEARCH_MODE_DATA_SHORTCUT || mode == SEARCH_MODE_CONTACT_SHORTCUT) {
+ return Directory.CONTENT_URI;
+ } else {
+ return DirectoryCompat.getContentUri();
+ }
+ }
+ }
+
+ // This is a virtual column created for a MatrixCursor.
+ public static final String DIRECTORY_TYPE = "directoryType";
+
+ private static final String[] RESULT_PROJECTION = {
+ Directory._ID,
+ DIRECTORY_TYPE,
+ Directory.DISPLAY_NAME,
+ Directory.PHOTO_SUPPORT,
+ };
+
+ private final ContentObserver mObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ forceLoad();
+ }
+ };
+
+ private int mDirectorySearchMode;
+ private boolean mLocalInvisibleDirectoryEnabled;
+
+ private MatrixCursor mDefaultDirectoryList;
+
+ public DirectoryListLoader(Context context) {
+ super(context);
+ }
+
+ public void setDirectorySearchMode(int mode) {
+ mDirectorySearchMode = mode;
+ }
+
+ /**
+ * A flag that indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should
+ * be included in the results.
+ */
+ public void setLocalInvisibleDirectoryEnabled(boolean flag) {
+ this.mLocalInvisibleDirectoryEnabled = flag;
+ }
+
+ @Override
+ protected void onStartLoading() {
+ getContext().getContentResolver().
+ registerContentObserver(DirectoryQuery.getDirectoryUri(mDirectorySearchMode),
+ false, mObserver);
+ forceLoad();
+ }
+
+ @Override
+ protected void onStopLoading() {
+ getContext().getContentResolver().unregisterContentObserver(mObserver);
+ }
+
+ @Override
+ public Cursor loadInBackground() {
+ if (mDirectorySearchMode == SEARCH_MODE_NONE) {
+ return getDefaultDirectories();
+ }
+
+ MatrixCursor result = new MatrixCursor(RESULT_PROJECTION);
+ Context context = getContext();
+ PackageManager pm = context.getPackageManager();
+ String selection;
+ switch (mDirectorySearchMode) {
+ case SEARCH_MODE_DEFAULT:
+ selection = null;
+ break;
+
+ case SEARCH_MODE_CONTACT_SHORTCUT:
+ selection = Directory.SHORTCUT_SUPPORT + "=" + Directory.SHORTCUT_SUPPORT_FULL;
+ break;
+
+ case SEARCH_MODE_DATA_SHORTCUT:
+ selection = Directory.SHORTCUT_SUPPORT + " IN ("
+ + Directory.SHORTCUT_SUPPORT_FULL + ", "
+ + Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY + ")";
+ break;
+
+ default:
+ throw new RuntimeException(
+ "Unsupported directory search mode: " + mDirectorySearchMode);
+ }
+ Cursor cursor = null;
+ try {
+ cursor = context.getContentResolver().query(
+ DirectoryQuery.getDirectoryUri(mDirectorySearchMode),
+ DirectoryQuery.PROJECTION, selection, null, DirectoryQuery.ORDER_BY);
+
+ if (cursor == null) {
+ return result;
+ }
+
+ while(cursor.moveToNext()) {
+ long directoryId = cursor.getLong(DirectoryQuery.ID);
+ if (!mLocalInvisibleDirectoryEnabled
+ && DirectoryCompat.isInvisibleDirectory(directoryId)) {
+ continue;
+ }
+ String directoryType = null;
+
+ String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
+ int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
+ if (!TextUtils.isEmpty(packageName) && typeResourceId != 0) {
+ try {
+ directoryType = pm.getResourcesForApplication(packageName)
+ .getString(typeResourceId);
+ } catch (Exception e) {
+ Log.e(TAG, "Cannot obtain directory type from package: " + packageName);
+ }
+ }
+ String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
+ int photoSupport = cursor.getInt(DirectoryQuery.PHOTO_SUPPORT);
+ result.addRow(new Object[]{directoryId, directoryType, displayName, photoSupport});
+ }
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Runtime Exception when querying directory");
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ return result;
+ }
+
+ private Cursor getDefaultDirectories() {
+ if (mDefaultDirectoryList == null) {
+ mDefaultDirectoryList = new MatrixCursor(RESULT_PROJECTION);
+ mDefaultDirectoryList.addRow(new Object[] {
+ Directory.DEFAULT,
+ getContext().getString(R.string.contactsList),
+ null
+ });
+ mDefaultDirectoryList.addRow(new Object[] {
+ Directory.LOCAL_INVISIBLE,
+ getContext().getString(R.string.local_invisible_directory),
+ null
+ });
+ }
+ return mDefaultDirectoryList;
+ }
+
+ @Override
+ protected void onReset() {
+ stopLoading();
+ }
+}
diff --git a/src/com/android/contacts/common/list/DirectoryPartition.java b/src/com/android/contacts/common/list/DirectoryPartition.java
new file mode 100644
index 0000000..ca0dc11
--- /dev/null
+++ b/src/com/android/contacts/common/list/DirectoryPartition.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.provider.ContactsContract.Directory;
+
+import com.android.common.widget.CompositeCursorAdapter;
+
+/**
+ * Model object for a {@link Directory} row.
+ */
+public final class DirectoryPartition extends CompositeCursorAdapter.Partition {
+
+ public static final int STATUS_NOT_LOADED = 0;
+ public static final int STATUS_LOADING = 1;
+ public static final int STATUS_LOADED = 2;
+
+ public static final int RESULT_LIMIT_DEFAULT = -1;
+
+ private long mDirectoryId;
+ private String mContentUri;
+ private String mDirectoryType;
+ private String mDisplayName;
+ private int mStatus;
+ private boolean mPriorityDirectory;
+ private boolean mPhotoSupported;
+ private int mResultLimit = RESULT_LIMIT_DEFAULT;
+ private boolean mDisplayNumber = true;
+
+ private String mLabel;
+
+ public DirectoryPartition(boolean showIfEmpty, boolean hasHeader) {
+ super(showIfEmpty, hasHeader);
+ }
+
+ /**
+ * Directory ID, see {@link Directory}.
+ */
+ public long getDirectoryId() {
+ return mDirectoryId;
+ }
+
+ public void setDirectoryId(long directoryId) {
+ this.mDirectoryId = directoryId;
+ }
+
+ /**
+ * Directory type resolved from {@link Directory#PACKAGE_NAME} and
+ * {@link Directory#TYPE_RESOURCE_ID};
+ */
+ public String getDirectoryType() {
+ return mDirectoryType;
+ }
+
+ public void setDirectoryType(String directoryType) {
+ this.mDirectoryType = directoryType;
+ }
+
+ /**
+ * See {@link Directory#DISPLAY_NAME}.
+ */
+ public String getDisplayName() {
+ return mDisplayName;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.mDisplayName = displayName;
+ }
+
+ public int getStatus() {
+ return mStatus;
+ }
+
+ public void setStatus(int status) {
+ mStatus = status;
+ }
+
+ public boolean isLoading() {
+ return mStatus == STATUS_NOT_LOADED || mStatus == STATUS_LOADING;
+ }
+
+ /**
+ * Returns true if this directory should be loaded before non-priority directories.
+ */
+ public boolean isPriorityDirectory() {
+ return mPriorityDirectory;
+ }
+
+ public void setPriorityDirectory(boolean priorityDirectory) {
+ mPriorityDirectory = priorityDirectory;
+ }
+
+ /**
+ * Returns true if this directory supports photos.
+ */
+ public boolean isPhotoSupported() {
+ return mPhotoSupported;
+ }
+
+ public void setPhotoSupported(boolean flag) {
+ this.mPhotoSupported = flag;
+ }
+
+ /**
+ * Max number of results for this directory. Defaults to {@link #RESULT_LIMIT_DEFAULT} which
+ * implies using the adapter's
+ * {@link com.android.contacts.common.list.ContactListAdapter#getDirectoryResultLimit()}
+ */
+ public int getResultLimit() {
+ return mResultLimit;
+ }
+
+ public void setResultLimit(int resultLimit) {
+ mResultLimit = resultLimit;
+ }
+
+ /**
+ * Used by extended directories to specify a custom content URI. Extended directories MUST have
+ * a content URI
+ */
+ public String getContentUri() {
+ return mContentUri;
+ }
+
+ public void setContentUri(String contentUri) {
+ mContentUri = contentUri;
+ }
+
+ /**
+ * A label to display in the header next to the display name.
+ */
+ public String getLabel() {
+ return mLabel;
+ }
+
+ public void setLabel(String label) {
+ mLabel = label;
+ }
+
+ @Override
+ public String toString() {
+ return "DirectoryPartition{" +
+ "mDirectoryId=" + mDirectoryId +
+ ", mContentUri='" + mContentUri + '\'' +
+ ", mDirectoryType='" + mDirectoryType + '\'' +
+ ", mDisplayName='" + mDisplayName + '\'' +
+ ", mStatus=" + mStatus +
+ ", mPriorityDirectory=" + mPriorityDirectory +
+ ", mPhotoSupported=" + mPhotoSupported +
+ ", mResultLimit=" + mResultLimit +
+ ", mLabel='" + mLabel + '\'' +
+ '}';
+ }
+
+ /**
+ * Whether or not to display the phone number in app that have that option - Dialer. If false,
+ * Phone Label should be used instead of Phone Number.
+ */
+ public boolean isDisplayNumber() {
+ return mDisplayNumber;
+ }
+
+ public void setDisplayNumber(boolean displayNumber) {
+ mDisplayNumber = displayNumber;
+ }
+}
diff --git a/src/com/android/contacts/common/list/FavoritesAndContactsLoader.java b/src/com/android/contacts/common/list/FavoritesAndContactsLoader.java
new file mode 100644
index 0000000..d1ae911
--- /dev/null
+++ b/src/com/android/contacts/common/list/FavoritesAndContactsLoader.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2011 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.common.list;
+
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.Cursor;
+import android.database.MergeCursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract.Contacts;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * A loader for use in the default contact list, which will also query for favorite contacts
+ * if configured to do so.
+ */
+public class FavoritesAndContactsLoader extends CursorLoader {
+
+ private boolean mLoadFavorites;
+
+ private String[] mProjection;
+
+ private Uri mExtraUri;
+ private String[] mExtraProjection;
+ private String mExtraSelection;
+ private String[] mExtraSelectionArgs;
+ private boolean mMergeExtraContactsAfterPrimary;
+
+ public FavoritesAndContactsLoader(Context context) {
+ super(context);
+ }
+
+ /** Whether to load favorites and merge results in before any other results. */
+ public void setLoadFavorites(boolean flag) {
+ mLoadFavorites = flag;
+ }
+
+ public void setProjection(String[] projection) {
+ super.setProjection(projection);
+ mProjection = projection;
+ }
+
+ /** Configure an extra query and merge results in before the primary results. */
+ public void setLoadExtraContactsFirst(Uri uri, String[] projection) {
+ mExtraUri = uri;
+ mExtraProjection = projection;
+ mMergeExtraContactsAfterPrimary = false;
+ }
+
+ /** Configure an extra query and merge results in after the primary results. */
+ public void setLoadExtraContactsLast(Uri uri, String[] projection, String selection,
+ String[] selectionArgs) {
+ mExtraUri = uri;
+ mExtraProjection = projection;
+ mExtraSelection = selection;
+ mExtraSelectionArgs = selectionArgs;
+ mMergeExtraContactsAfterPrimary = true;
+ }
+
+ private boolean canLoadExtraContacts() {
+ return mExtraUri != null && mExtraProjection != null;
+ }
+
+ @Override
+ public Cursor loadInBackground() {
+ List<Cursor> cursors = Lists.newArrayList();
+ if (mLoadFavorites) {
+ cursors.add(loadFavoritesContacts());
+ }
+ if (canLoadExtraContacts() && !mMergeExtraContactsAfterPrimary) {
+ cursors.add(loadExtraContacts());
+ }
+ // ContactsCursor.loadInBackground() can return null; MergeCursor
+ // correctly handles null cursors.
+ Cursor cursor = null;
+ try {
+ cursor = super.loadInBackground();
+ } catch (NullPointerException | SecurityException e) {
+ // Ignore NPEs and SecurityExceptions thrown by providers
+ }
+ final Cursor contactsCursor = cursor;
+ cursors.add(contactsCursor);
+ if (canLoadExtraContacts() && mMergeExtraContactsAfterPrimary) {
+ cursors.add(loadExtraContacts());
+ }
+ return new MergeCursor(cursors.toArray(new Cursor[cursors.size()])) {
+ @Override
+ public Bundle getExtras() {
+ // Need to get the extras from the contacts cursor.
+ return contactsCursor == null ? new Bundle() : contactsCursor.getExtras();
+ }
+ };
+ }
+
+ private Cursor loadExtraContacts() {
+ return getContext().getContentResolver().query(
+ mExtraUri, mExtraProjection, mExtraSelection, mExtraSelectionArgs, null);
+ }
+
+ private Cursor loadFavoritesContacts() {
+ return getContext().getContentResolver().query(
+ Contacts.CONTENT_URI, mProjection, Contacts.STARRED + "=?", new String[]{"1"},
+ getSortOrder());
+ }
+}
diff --git a/src/com/android/contacts/common/list/IndexerListAdapter.java b/src/com/android/contacts/common/list/IndexerListAdapter.java
new file mode 100644
index 0000000..032bb53
--- /dev/null
+++ b/src/com/android/contacts/common/list/IndexerListAdapter.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListView;
+import android.widget.SectionIndexer;
+
+/**
+ * A list adapter that supports section indexer and a pinned header.
+ */
+public abstract class IndexerListAdapter extends PinnedHeaderListAdapter implements SectionIndexer {
+
+ protected Context mContext;
+ private SectionIndexer mIndexer;
+ private int mIndexedPartition = 0;
+ private boolean mSectionHeaderDisplayEnabled;
+ private View mHeader;
+
+ /**
+ * An item view is displayed differently depending on whether it is placed
+ * at the beginning, middle or end of a section. It also needs to know the
+ * section header when it is at the beginning of a section. This object
+ * captures all this configuration.
+ */
+ public static final class Placement {
+ private int position = ListView.INVALID_POSITION;
+ public boolean firstInSection;
+ public boolean lastInSection;
+ public String sectionHeader;
+
+ public void invalidate() {
+ position = ListView.INVALID_POSITION;
+ }
+ }
+
+ private Placement mPlacementCache = new Placement();
+
+ /**
+ * Constructor.
+ */
+ public IndexerListAdapter(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ /**
+ * Creates a section header view that will be pinned at the top of the list
+ * as the user scrolls.
+ */
+ protected abstract View createPinnedSectionHeaderView(Context context, ViewGroup parent);
+
+ /**
+ * Sets the title in the pinned header as the user scrolls.
+ */
+ protected abstract void setPinnedSectionTitle(View pinnedHeaderView, String title);
+
+ public boolean isSectionHeaderDisplayEnabled() {
+ return mSectionHeaderDisplayEnabled;
+ }
+
+ public void setSectionHeaderDisplayEnabled(boolean flag) {
+ this.mSectionHeaderDisplayEnabled = flag;
+ }
+
+ public int getIndexedPartition() {
+ return mIndexedPartition;
+ }
+
+ public void setIndexedPartition(int partition) {
+ this.mIndexedPartition = partition;
+ }
+
+ public SectionIndexer getIndexer() {
+ return mIndexer;
+ }
+
+ public void setIndexer(SectionIndexer indexer) {
+ mIndexer = indexer;
+ mPlacementCache.invalidate();
+ }
+
+ public Object[] getSections() {
+ if (mIndexer == null) {
+ return new String[] { " " };
+ } else {
+ return mIndexer.getSections();
+ }
+ }
+
+ /**
+ * @return relative position of the section in the indexed partition
+ */
+ public int getPositionForSection(int sectionIndex) {
+ if (mIndexer == null) {
+ return -1;
+ }
+
+ return mIndexer.getPositionForSection(sectionIndex);
+ }
+
+ /**
+ * @param position relative position in the indexed partition
+ */
+ public int getSectionForPosition(int position) {
+ if (mIndexer == null) {
+ return -1;
+ }
+
+ return mIndexer.getSectionForPosition(position);
+ }
+
+ @Override
+ public int getPinnedHeaderCount() {
+ if (isSectionHeaderDisplayEnabled()) {
+ return super.getPinnedHeaderCount() + 1;
+ } else {
+ return super.getPinnedHeaderCount();
+ }
+ }
+
+ @Override
+ public View getPinnedHeaderView(int viewIndex, View convertView, ViewGroup parent) {
+ if (isSectionHeaderDisplayEnabled() && viewIndex == getPinnedHeaderCount() - 1) {
+ if (mHeader == null) {
+ mHeader = createPinnedSectionHeaderView(mContext, parent);
+ }
+ return mHeader;
+ } else {
+ return super.getPinnedHeaderView(viewIndex, convertView, parent);
+ }
+ }
+
+ @Override
+ public void configurePinnedHeaders(PinnedHeaderListView listView) {
+ super.configurePinnedHeaders(listView);
+
+ if (!isSectionHeaderDisplayEnabled()) {
+ return;
+ }
+
+ int index = getPinnedHeaderCount() - 1;
+ if (mIndexer == null || getCount() == 0) {
+ listView.setHeaderInvisible(index, false);
+ } else {
+ int listPosition = listView.getPositionAt(listView.getTotalTopPinnedHeaderHeight());
+ int position = listPosition - listView.getHeaderViewsCount();
+
+ int section = -1;
+ int partition = getPartitionForPosition(position);
+ if (partition == mIndexedPartition) {
+ int offset = getOffsetInPartition(position);
+ if (offset != -1) {
+ section = getSectionForPosition(offset);
+ }
+ }
+
+ if (section == -1) {
+ listView.setHeaderInvisible(index, false);
+ } else {
+ View topChild = listView.getChildAt(listPosition);
+ if (topChild != null) {
+ // Match the pinned header's height to the height of the list item.
+ mHeader.setMinimumHeight(topChild.getMeasuredHeight());
+ }
+ setPinnedSectionTitle(mHeader, (String)mIndexer.getSections()[section]);
+
+ // Compute the item position where the current partition begins
+ int partitionStart = getPositionForPartition(mIndexedPartition);
+ if (hasHeader(mIndexedPartition)) {
+ partitionStart++;
+ }
+
+ // Compute the item position where the next section begins
+ int nextSectionPosition = partitionStart + getPositionForSection(section + 1);
+ boolean isLastInSection = position == nextSectionPosition - 1;
+ listView.setFadingHeader(index, listPosition, isLastInSection);
+ }
+ }
+ }
+
+ /**
+ * Computes the item's placement within its section and populates the {@code placement}
+ * object accordingly. Please note that the returned object is volatile and should be
+ * copied if the result needs to be used later.
+ */
+ public Placement getItemPlacementInSection(int position) {
+ if (mPlacementCache.position == position) {
+ return mPlacementCache;
+ }
+
+ mPlacementCache.position = position;
+ if (isSectionHeaderDisplayEnabled()) {
+ int section = getSectionForPosition(position);
+ if (section != -1 && getPositionForSection(section) == position) {
+ mPlacementCache.firstInSection = true;
+ mPlacementCache.sectionHeader = (String)getSections()[section];
+ } else {
+ mPlacementCache.firstInSection = false;
+ mPlacementCache.sectionHeader = null;
+ }
+
+ mPlacementCache.lastInSection = (getPositionForSection(section + 1) - 1 == position);
+ } else {
+ mPlacementCache.firstInSection = false;
+ mPlacementCache.lastInSection = false;
+ mPlacementCache.sectionHeader = null;
+ }
+ return mPlacementCache;
+ }
+}
diff --git a/src/com/android/contacts/common/list/MultiSelectEntryContactListAdapter.java b/src/com/android/contacts/common/list/MultiSelectEntryContactListAdapter.java
new file mode 100644
index 0000000..9ab6e1c
--- /dev/null
+++ b/src/com/android/contacts/common/list/MultiSelectEntryContactListAdapter.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2015 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.common.list;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.ContactsContract;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.CheckBox;
+
+import java.util.TreeSet;
+
+/**
+ * An extension of the default contact adapter that adds checkboxes and the ability
+ * to select multiple contacts.
+ */
+public abstract class MultiSelectEntryContactListAdapter extends ContactEntryListAdapter {
+
+ private SelectedContactsListener mSelectedContactsListener;
+ private DeleteContactListener mDeleteContactListener;
+ private TreeSet<Long> mSelectedContactIds = new TreeSet<Long>();
+ private boolean mDisplayCheckBoxes;
+ private final int mContactIdColumnIndex;
+
+ public interface SelectedContactsListener {
+ void onSelectedContactsChanged();
+ void onSelectedContactsChangedViaCheckBox();
+ }
+
+ public interface DeleteContactListener {
+ void onContactDeleteClicked(int position);
+ }
+
+ /**
+ * @param contactIdColumnIndex the column index of the contact ID in the underlying cursor;
+ * it is passed in so that this adapter can support different kinds of contact
+ * lists (e.g. aggregate contacts or raw contacts).
+ */
+ public MultiSelectEntryContactListAdapter(Context context, int contactIdColumnIndex) {
+ super(context);
+ mContactIdColumnIndex = contactIdColumnIndex;
+ }
+
+ /**
+ * Returns the column index of the contact ID in the underlying cursor; the contact ID
+ * retrieved using this index is the value that is selected by this adapter (and returned
+ * by {@link #getSelectedContactIds}).
+ */
+ public int getContactColumnIdIndex() {
+ return mContactIdColumnIndex;
+ }
+
+ public DeleteContactListener getDeleteContactListener() {
+ return mDeleteContactListener;
+ }
+
+ public void setDeleteContactListener(DeleteContactListener deleteContactListener) {
+ mDeleteContactListener = deleteContactListener;
+ }
+
+ public void setSelectedContactsListener(SelectedContactsListener listener) {
+ mSelectedContactsListener = listener;
+ }
+
+ /**
+ * Returns set of selected contacts.
+ */
+ public TreeSet<Long> getSelectedContactIds() {
+ return mSelectedContactIds;
+ }
+
+ /**
+ * Returns the selected contacts as an array.
+ */
+ public long[] getSelectedContactIdsArray() {
+ final Long[] contactIds = mSelectedContactIds.toArray(
+ new Long[mSelectedContactIds.size()]);
+ final long[] result = new long[contactIds.length];
+ for (int i = 0; i < contactIds.length; i++) {
+ result[i] = contactIds[i];
+ }
+ return result;
+ }
+
+ /**
+ * Update set of selected contacts. This changes which checkboxes are set.
+ */
+ public void setSelectedContactIds(TreeSet<Long> selectedContactIds) {
+ this.mSelectedContactIds = selectedContactIds;
+ notifyDataSetChanged();
+ if (mSelectedContactsListener != null) {
+ mSelectedContactsListener.onSelectedContactsChanged();
+ }
+ }
+
+ /**
+ * Shows checkboxes beside contacts if {@param displayCheckBoxes} is {@code TRUE}.
+ * Not guaranteed to work with all configurations of this adapter.
+ */
+ public void setDisplayCheckBoxes(boolean showCheckBoxes) {
+ if (!mDisplayCheckBoxes && showCheckBoxes) {
+ setSelectedContactIds(new TreeSet<Long>());
+ }
+ mDisplayCheckBoxes = showCheckBoxes;
+ notifyDataSetChanged();
+ if (mSelectedContactsListener != null) {
+ mSelectedContactsListener.onSelectedContactsChanged();
+ }
+ }
+
+ /**
+ * Checkboxes are being displayed beside contacts.
+ */
+ public boolean isDisplayingCheckBoxes() {
+ return mDisplayCheckBoxes;
+ }
+
+ /**
+ * Toggle the checkbox beside the contact for {@param contactId}.
+ */
+ public void toggleSelectionOfContactId(long contactId) {
+ if (mSelectedContactIds.contains(contactId)) {
+ mSelectedContactIds.remove(contactId);
+ } else {
+ mSelectedContactIds.add(contactId);
+ }
+ notifyDataSetChanged();
+ if (mSelectedContactsListener != null) {
+ mSelectedContactsListener.onSelectedContactsChanged();
+ }
+ }
+
+ @Override
+ public long getItemId(int position) {
+ Cursor cursor = (Cursor) getItem(position);
+ if (cursor != null) {
+ return cursor.getLong(getContactColumnIdIndex());
+ }
+ return 0;
+ }
+
+ @Override
+ protected void bindView(View itemView, int partition, Cursor cursor, int position) {
+ super.bindView(itemView, partition, cursor, position);
+ final ContactListItemView view = (ContactListItemView) itemView;
+ bindViewId(view, cursor, getContactColumnIdIndex());
+ bindCheckBox(view, cursor, position, partition == ContactsContract.Directory.DEFAULT);
+ }
+
+ private void bindCheckBox(ContactListItemView view, Cursor cursor, int position,
+ boolean isLocalDirectory) {
+ // Disable clicking on all contacts from remote directories when showing check boxes. We do
+ // this by telling the view to handle clicking itself.
+ view.setClickable(!isLocalDirectory && mDisplayCheckBoxes);
+ // Only show checkboxes if mDisplayCheckBoxes is enabled. Also, never show the
+ // checkbox for other directory contacts except local directory.
+ if (!mDisplayCheckBoxes || !isLocalDirectory) {
+ view.hideCheckBox();
+ return;
+ }
+ final CheckBox checkBox = view.getCheckBox();
+ final long contactId = cursor.getLong(mContactIdColumnIndex);
+ checkBox.setChecked(mSelectedContactIds.contains(contactId));
+ checkBox.setTag(contactId);
+ checkBox.setOnClickListener(mCheckBoxClickListener);
+ }
+
+ private final OnClickListener mCheckBoxClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final CheckBox checkBox = (CheckBox) v;
+ final Long contactId = (Long) checkBox.getTag();
+ if (checkBox.isChecked()) {
+ mSelectedContactIds.add(contactId);
+ } else {
+ mSelectedContactIds.remove(contactId);
+ }
+ notifyDataSetChanged();
+ if (mSelectedContactsListener != null) {
+ mSelectedContactsListener.onSelectedContactsChangedViaCheckBox();
+ }
+ }
+ };
+}
diff --git a/src/com/android/contacts/common/list/OnPhoneNumberPickerActionListener.java b/src/com/android/contacts/common/list/OnPhoneNumberPickerActionListener.java
new file mode 100644
index 0000000..fe23054
--- /dev/null
+++ b/src/com/android/contacts/common/list/OnPhoneNumberPickerActionListener.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.app.ActionBar;
+import android.content.Intent;
+import android.net.Uri;
+
+/**
+ * Action callbacks that can be sent by a phone number picker.
+ */
+public interface OnPhoneNumberPickerActionListener {
+ public static final int CALL_INITIATION_UNKNOWN = 0;
+
+ /**
+ * Returns the selected phone number uri to the requester.
+ */
+ void onPickDataUri(Uri dataUri, boolean isVideoCall, int callInitiationType);
+
+ /**
+ * Returns the specified phone number to the requester.
+ * May call the specified phone number, either as an audio or video call.
+ */
+ void onPickPhoneNumber(String phoneNumber, boolean isVideoCall, int callInitiationType);
+
+ /**
+ * Returns the selected number as a shortcut intent.
+ */
+ void onShortcutIntentCreated(Intent intent);
+
+ /**
+ * Called when home menu in {@link ActionBar} is clicked by the user.
+ */
+ void onHomeInActionBarSelected();
+}
diff --git a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
new file mode 100644
index 0000000..348cac2
--- /dev/null
+++ b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.net.Uri.Builder;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Callable;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Directory;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.contacts.common.CallUtil;
+import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.GeoUtil;
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.CallableCompat;
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.compat.DirectoryCompat;
+import com.android.contacts.common.compat.PhoneCompat;
+import com.android.contacts.common.extensions.ExtendedPhoneDirectoriesManager;
+import com.android.contacts.common.extensions.ExtensionsFactory;
+import com.android.contacts.common.preference.ContactsPreferences;
+import com.android.contacts.common.util.Constants;
+
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A cursor adapter for the {@link Phone#CONTENT_ITEM_TYPE} and
+ * {@link SipAddress#CONTENT_ITEM_TYPE}.
+ *
+ * By default this adapter just handles phone numbers. When {@link #setUseCallableUri(boolean)} is
+ * called with "true", this adapter starts handling SIP addresses too, by using {@link Callable}
+ * API instead of {@link Phone}.
+ */
+public class PhoneNumberListAdapter extends ContactEntryListAdapter {
+
+ private static final String TAG = PhoneNumberListAdapter.class.getSimpleName();
+
+ public interface Listener {
+ void onVideoCallIconClicked(int position);
+ }
+
+ // A list of extended directories to add to the directories from the database
+ private final List<DirectoryPartition> mExtendedDirectories;
+
+ // Extended directories will have ID's that are higher than any of the id's from the database,
+ // so that we can identify them and set them up properly. If no extended directories
+ // exist, this will be Long.MAX_VALUE
+ private long mFirstExtendedDirectoryId = Long.MAX_VALUE;
+
+ public static class PhoneQuery {
+
+ /**
+ * Optional key used as part of a JSON lookup key to specify an analytics category
+ * associated with the row.
+ */
+ public static final String ANALYTICS_CATEGORY = "analytics_category";
+
+ /**
+ * Optional key used as part of a JSON lookup key to specify an analytics action associated
+ * with the row.
+ */
+ public static final String ANALYTICS_ACTION = "analytics_action";
+
+ /**
+ * Optional key used as part of a JSON lookup key to specify an analytics value associated
+ * with the row.
+ */
+ public static final String ANALYTICS_VALUE = "analytics_value";
+
+ public static final String[] PROJECTION_PRIMARY_INTERNAL = new String[] {
+ Phone._ID, // 0
+ Phone.TYPE, // 1
+ Phone.LABEL, // 2
+ Phone.NUMBER, // 3
+ Phone.CONTACT_ID, // 4
+ Phone.LOOKUP_KEY, // 5
+ Phone.PHOTO_ID, // 6
+ Phone.DISPLAY_NAME_PRIMARY, // 7
+ Phone.PHOTO_THUMBNAIL_URI, // 8
+ };
+
+ public static final String[] PROJECTION_PRIMARY;
+
+ static {
+ final List<String> projectionList = Lists.newArrayList(PROJECTION_PRIMARY_INTERNAL);
+ if (CompatUtils.isMarshmallowCompatible()) {
+ projectionList.add(Phone.CARRIER_PRESENCE); // 9
+ }
+ PROJECTION_PRIMARY = projectionList.toArray(new String[projectionList.size()]);
+ }
+
+ public static final String[] PROJECTION_ALTERNATIVE_INTERNAL = new String[] {
+ Phone._ID, // 0
+ Phone.TYPE, // 1
+ Phone.LABEL, // 2
+ Phone.NUMBER, // 3
+ Phone.CONTACT_ID, // 4
+ Phone.LOOKUP_KEY, // 5
+ Phone.PHOTO_ID, // 6
+ Phone.DISPLAY_NAME_ALTERNATIVE, // 7
+ Phone.PHOTO_THUMBNAIL_URI, // 8
+ };
+
+ public static final String[] PROJECTION_ALTERNATIVE;
+
+ static {
+ final List<String> projectionList = Lists.newArrayList(PROJECTION_ALTERNATIVE_INTERNAL);
+ if (CompatUtils.isMarshmallowCompatible()) {
+ projectionList.add(Phone.CARRIER_PRESENCE); // 9
+ }
+ PROJECTION_ALTERNATIVE = projectionList.toArray(new String[projectionList.size()]);
+ }
+
+ public static final int PHONE_ID = 0;
+ public static final int PHONE_TYPE = 1;
+ public static final int PHONE_LABEL = 2;
+ public static final int PHONE_NUMBER = 3;
+ public static final int CONTACT_ID = 4;
+ public static final int LOOKUP_KEY = 5;
+ public static final int PHOTO_ID = 6;
+ public static final int DISPLAY_NAME = 7;
+ public static final int PHOTO_URI = 8;
+ public static final int CARRIER_PRESENCE = 9;
+ }
+
+ private static final String IGNORE_NUMBER_TOO_LONG_CLAUSE =
+ "length(" + Phone.NUMBER + ") < 1000";
+
+ private final CharSequence mUnknownNameText;
+ private final String mCountryIso;
+
+ private ContactListItemView.PhotoPosition mPhotoPosition;
+
+ private boolean mUseCallableUri;
+
+ private Listener mListener;
+
+ private boolean mIsVideoEnabled;
+ private boolean mIsPresenceEnabled;
+
+ public PhoneNumberListAdapter(Context context) {
+ super(context);
+ setDefaultFilterHeaderText(R.string.list_filter_phones);
+ mUnknownNameText = context.getText(android.R.string.unknownName);
+ mCountryIso = GeoUtil.getCurrentCountryIso(context);
+
+ final ExtendedPhoneDirectoriesManager manager
+ = ExtensionsFactory.getExtendedPhoneDirectoriesManager();
+ if (manager != null) {
+ mExtendedDirectories = manager.getExtendedDirectories(mContext);
+ } else {
+ // Empty list to avoid sticky NPE's
+ mExtendedDirectories = new ArrayList<DirectoryPartition>();
+ }
+
+ int videoCapabilities = CallUtil.getVideoCallingAvailability(context);
+ mIsVideoEnabled = (videoCapabilities & CallUtil.VIDEO_CALLING_ENABLED) != 0;
+ mIsPresenceEnabled = (videoCapabilities & CallUtil.VIDEO_CALLING_PRESENCE) != 0;
+ }
+
+ protected CharSequence getUnknownNameText() {
+ return mUnknownNameText;
+ }
+
+ @Override
+ public void configureLoader(CursorLoader loader, long directoryId) {
+ String query = getQueryString();
+ if (query == null) {
+ query = "";
+ }
+ if (isExtendedDirectory(directoryId)) {
+ final DirectoryPartition directory = getExtendedDirectoryFromId(directoryId);
+ final String contentUri = directory.getContentUri();
+ if (contentUri == null) {
+ throw new IllegalStateException("Extended directory must have a content URL: "
+ + directory);
+ }
+ final Builder builder = Uri.parse(contentUri).buildUpon();
+ builder.appendPath(query);
+ builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(getDirectoryResultLimit(directory)));
+ loader.setUri(builder.build());
+ loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
+ } else {
+ final boolean isRemoteDirectoryQuery
+ = DirectoryCompat.isRemoteDirectoryId(directoryId);
+ final Builder builder;
+ if (isSearchMode()) {
+ final Uri baseUri;
+ if (isRemoteDirectoryQuery) {
+ baseUri = PhoneCompat.getContentFilterUri();
+ } else if (mUseCallableUri) {
+ baseUri = CallableCompat.getContentFilterUri();
+ } else {
+ baseUri = PhoneCompat.getContentFilterUri();
+ }
+ builder = baseUri.buildUpon();
+ builder.appendPath(query); // Builder will encode the query
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ if (isRemoteDirectoryQuery) {
+ builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
+ }
+ } else {
+ Uri baseUri = mUseCallableUri ? Callable.CONTENT_URI : Phone.CONTENT_URI;
+ builder = baseUri.buildUpon().appendQueryParameter(
+ ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT));
+ if (isSectionHeaderDisplayEnabled()) {
+ builder.appendQueryParameter(Phone.EXTRA_ADDRESS_BOOK_INDEX, "true");
+ }
+ applyFilter(loader, builder, directoryId, getFilter());
+ }
+
+ // Ignore invalid phone numbers that are too long. These can potentially cause freezes
+ // in the UI and there is no reason to display them.
+ final String prevSelection = loader.getSelection();
+ final String newSelection;
+ if (!TextUtils.isEmpty(prevSelection)) {
+ newSelection = prevSelection + " AND " + IGNORE_NUMBER_TOO_LONG_CLAUSE;
+ } else {
+ newSelection = IGNORE_NUMBER_TOO_LONG_CLAUSE;
+ }
+ loader.setSelection(newSelection);
+
+ // Remove duplicates when it is possible.
+ builder.appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true");
+ loader.setUri(builder.build());
+
+ // TODO a projection that includes the search snippet
+ if (getContactNameDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
+ loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
+ } else {
+ loader.setProjection(PhoneQuery.PROJECTION_ALTERNATIVE);
+ }
+
+ if (getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY) {
+ loader.setSortOrder(Phone.SORT_KEY_PRIMARY);
+ } else {
+ loader.setSortOrder(Phone.SORT_KEY_ALTERNATIVE);
+ }
+ }
+ }
+
+ protected boolean isExtendedDirectory(long directoryId) {
+ return directoryId >= mFirstExtendedDirectoryId;
+ }
+
+ private DirectoryPartition getExtendedDirectoryFromId(long directoryId) {
+ final int directoryIndex = (int) (directoryId - mFirstExtendedDirectoryId);
+ return mExtendedDirectories.get(directoryIndex);
+ }
+
+ /**
+ * Configure {@code loader} and {@code uriBuilder} according to {@code directoryId} and {@code
+ * filter}.
+ */
+ private void applyFilter(CursorLoader loader, Uri.Builder uriBuilder, long directoryId,
+ ContactListFilter filter) {
+ if (filter == null || directoryId != Directory.DEFAULT) {
+ return;
+ }
+
+ final StringBuilder selection = new StringBuilder();
+ final List<String> selectionArgs = new ArrayList<String>();
+
+ switch (filter.filterType) {
+ case ContactListFilter.FILTER_TYPE_CUSTOM: {
+ selection.append(Contacts.IN_VISIBLE_GROUP + "=1");
+ selection.append(" AND " + Contacts.HAS_PHONE_NUMBER + "=1");
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_ACCOUNT: {
+ filter.addAccountQueryParameterToUrl(uriBuilder);
+ break;
+ }
+ case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS:
+ case ContactListFilter.FILTER_TYPE_DEFAULT:
+ break; // No selection needed.
+ case ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY:
+ break; // This adapter is always "phone only", so no selection needed either.
+ default:
+ Log.w(TAG, "Unsupported filter type came " +
+ "(type: " + filter.filterType + ", toString: " + filter + ")" +
+ " showing all contacts.");
+ // No selection.
+ break;
+ }
+ loader.setSelection(selection.toString());
+ loader.setSelectionArgs(selectionArgs.toArray(new String[0]));
+ }
+
+ @Override
+ public String getContactDisplayName(int position) {
+ return ((Cursor) getItem(position)).getString(PhoneQuery.DISPLAY_NAME);
+ }
+
+ public String getPhoneNumber(int position) {
+ final Cursor item = (Cursor)getItem(position);
+ return item != null ? item.getString(PhoneQuery.PHONE_NUMBER) : null;
+ }
+
+ /**
+ * Builds a {@link Data#CONTENT_URI} for the given cursor position.
+ *
+ * @return Uri for the data. may be null if the cursor is not ready.
+ */
+ public Uri getDataUri(int position) {
+ final int partitionIndex = getPartitionForPosition(position);
+ final Cursor item = (Cursor)getItem(position);
+ return item != null ? getDataUri(partitionIndex, item) : null;
+ }
+
+ public Uri getDataUri(int partitionIndex, Cursor cursor) {
+ final long directoryId =
+ ((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId();
+ if (DirectoryCompat.isRemoteDirectoryId(directoryId)) {
+ return null;
+ } else if (DirectoryCompat.isEnterpriseDirectoryId(directoryId)) {
+ /*
+ * ContentUris.withAppendedId(Data.CONTENT_URI, phoneId), is invalid if
+ * isEnterpriseDirectoryId returns true, because the uri itself will fail since the
+ * ContactsProvider in Android Framework currently doesn't support it. return null until
+ * Android framework has enterprise version of Data.CONTENT_URI
+ */
+ return null;
+ } else {
+ final long phoneId = cursor.getLong(PhoneQuery.PHONE_ID);
+ return ContentUris.withAppendedId(Data.CONTENT_URI, phoneId);
+ }
+ }
+
+ /**
+ * Retrieves the lookup key for the given cursor position.
+ *
+ * @param position The cursor position.
+ * @return The lookup key.
+ */
+ public String getLookupKey(int position) {
+ final Cursor item = (Cursor)getItem(position);
+ return item != null ? item.getString(PhoneQuery.LOOKUP_KEY) : null;
+ }
+
+ @Override
+ protected ContactListItemView newView(
+ Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
+ ContactListItemView view = super.newView(context, partition, cursor, position, parent);
+ view.setUnknownNameText(mUnknownNameText);
+ view.setQuickContactEnabled(isQuickContactEnabled());
+ view.setPhotoPosition(mPhotoPosition);
+ return view;
+ }
+
+ protected void setHighlight(ContactListItemView view, Cursor cursor) {
+ view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);
+ }
+
+ // Override default, which would return number of phone numbers, so we
+ // instead return number of contacts.
+ @Override
+ protected int getResultCount(Cursor cursor) {
+ if (cursor == null) {
+ return 0;
+ }
+ cursor.moveToPosition(-1);
+ long curContactId = -1;
+ int numContacts = 0;
+ while(cursor.moveToNext()) {
+ final long contactId = cursor.getLong(PhoneQuery.CONTACT_ID);
+ if (contactId != curContactId) {
+ curContactId = contactId;
+ ++numContacts;
+ }
+ }
+ return numContacts;
+ }
+
+ @Override
+ protected void bindView(View itemView, int partition, Cursor cursor, int position) {
+ super.bindView(itemView, partition, cursor, position);
+ ContactListItemView view = (ContactListItemView)itemView;
+
+ setHighlight(view, cursor);
+
+ // Look at elements before and after this position, checking if contact IDs are same.
+ // If they have one same contact ID, it means they can be grouped.
+ //
+ // In one group, only the first entry will show its photo and its name, and the other
+ // entries in the group show just their data (e.g. phone number, email address).
+ cursor.moveToPosition(position);
+ boolean isFirstEntry = true;
+ boolean showBottomDivider = true;
+ final long currentContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
+ if (cursor.moveToPrevious() && !cursor.isBeforeFirst()) {
+ final long previousContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
+ if (currentContactId == previousContactId) {
+ isFirstEntry = false;
+ }
+ }
+ cursor.moveToPosition(position);
+ if (cursor.moveToNext() && !cursor.isAfterLast()) {
+ final long nextContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
+ if (currentContactId == nextContactId) {
+ // The following entry should be in the same group, which means we don't want a
+ // divider between them.
+ // TODO: we want a different divider than the divider between groups. Just hiding
+ // this divider won't be enough.
+ showBottomDivider = false;
+ }
+ }
+ cursor.moveToPosition(position);
+
+ bindViewId(view, cursor, PhoneQuery.PHONE_ID);
+
+ bindSectionHeaderAndDivider(view, position);
+ if (isFirstEntry) {
+ bindName(view, cursor);
+ if (isQuickContactEnabled()) {
+ bindQuickContact(view, partition, cursor, PhoneQuery.PHOTO_ID,
+ PhoneQuery.PHOTO_URI, PhoneQuery.CONTACT_ID,
+ PhoneQuery.LOOKUP_KEY, PhoneQuery.DISPLAY_NAME);
+ } else {
+ if (getDisplayPhotos()) {
+ bindPhoto(view, partition, cursor);
+ }
+ }
+ } else {
+ unbindName(view);
+
+ view.removePhotoView(true, false);
+ }
+
+ final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
+ bindPhoneNumber(view, cursor, directory.isDisplayNumber(), position);
+ }
+
+ protected void bindPhoneNumber(ContactListItemView view, Cursor cursor, boolean displayNumber,
+ int position) {
+ CharSequence label = null;
+ if (displayNumber && !cursor.isNull(PhoneQuery.PHONE_TYPE)) {
+ final int type = cursor.getInt(PhoneQuery.PHONE_TYPE);
+ final String customLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
+
+ // TODO cache
+ label = Phone.getTypeLabel(getContext().getResources(), type, customLabel);
+ }
+ view.setLabel(label);
+ final String text;
+ if (displayNumber) {
+ text = cursor.getString(PhoneQuery.PHONE_NUMBER);
+ } else {
+ // Display phone label. If that's null, display geocoded location for the number
+ final String phoneLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
+ if (phoneLabel != null) {
+ text = phoneLabel;
+ } else {
+ final String phoneNumber = cursor.getString(PhoneQuery.PHONE_NUMBER);
+ text = GeoUtil.getGeocodedLocationFor(mContext, phoneNumber);
+ }
+ }
+ view.setPhoneNumber(text, mCountryIso);
+
+ if (CompatUtils.isVideoCompatible()) {
+ // Determine if carrier presence indicates the number supports video calling.
+ int carrierPresence = cursor.getInt(PhoneQuery.CARRIER_PRESENCE);
+ boolean isPresent = (carrierPresence & Phone.CARRIER_PRESENCE_VT_CAPABLE) != 0;
+
+ boolean isVideoIconShown = mIsVideoEnabled && (
+ mIsPresenceEnabled && isPresent || !mIsPresenceEnabled);
+ view.setShowVideoCallIcon(isVideoIconShown, mListener, position);
+ }
+ }
+
+ protected void bindSectionHeaderAndDivider(final ContactListItemView view, int position) {
+ if (isSectionHeaderDisplayEnabled()) {
+ Placement placement = getItemPlacementInSection(position);
+ view.setSectionHeader(placement.firstInSection ? placement.sectionHeader : null);
+ } else {
+ view.setSectionHeader(null);
+ }
+ }
+
+ protected void bindName(final ContactListItemView view, Cursor cursor) {
+ view.showDisplayName(cursor, PhoneQuery.DISPLAY_NAME, getContactNameDisplayOrder());
+ // Note: we don't show phonetic names any more (see issue 5265330)
+ }
+
+ protected void unbindName(final ContactListItemView view) {
+ view.hideDisplayName();
+ }
+
+ @Override
+ protected void bindWorkProfileIcon(final ContactListItemView view, int partition) {
+ final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
+ final long directoryId = directory.getDirectoryId();
+ final long userType = ContactsUtils.determineUserType(directoryId, null);
+ // Work directory must not be a extended directory. An extended directory is custom
+ // directory in the app, but not a directory provided by framework. So it can't be
+ // USER_TYPE_WORK.
+ view.setWorkProfileIconEnabled(
+ !isExtendedDirectory(directoryId) && userType == ContactsUtils.USER_TYPE_WORK);
+ }
+
+ protected void bindPhoto(final ContactListItemView view, int partitionIndex, Cursor cursor) {
+ if (!isPhotoSupported(partitionIndex)) {
+ view.removePhotoView();
+ return;
+ }
+
+ long photoId = 0;
+ if (!cursor.isNull(PhoneQuery.PHOTO_ID)) {
+ photoId = cursor.getLong(PhoneQuery.PHOTO_ID);
+ }
+
+ if (photoId != 0) {
+ getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false,
+ getCircularPhotos(), null);
+ } else {
+ final String photoUriString = cursor.getString(PhoneQuery.PHOTO_URI);
+ final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
+
+ DefaultImageRequest request = null;
+ if (photoUri == null) {
+ final String displayName = cursor.getString(PhoneQuery.DISPLAY_NAME);
+ final String lookupKey = cursor.getString(PhoneQuery.LOOKUP_KEY);
+ request = new DefaultImageRequest(displayName, lookupKey, getCircularPhotos());
+ }
+ getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, false,
+ getCircularPhotos(), request);
+ }
+ }
+
+ public void setPhotoPosition(ContactListItemView.PhotoPosition photoPosition) {
+ mPhotoPosition = photoPosition;
+ }
+
+ public ContactListItemView.PhotoPosition getPhotoPosition() {
+ return mPhotoPosition;
+ }
+
+ public void setUseCallableUri(boolean useCallableUri) {
+ mUseCallableUri = useCallableUri;
+ }
+
+ public boolean usesCallableUri() {
+ return mUseCallableUri;
+ }
+
+ /**
+ * Override base implementation to inject extended directories between local & remote
+ * directories. This is done in the following steps:
+ * 1. Call base implementation to add directories from the cursor.
+ * 2. Iterate all base directories and establish the following information:
+ * a. The highest directory id so that we can assign unused id's to the extended directories.
+ * b. The index of the last non-remote directory. This is where we will insert extended
+ * directories.
+ * 3. Iterate the extended directories and for each one, assign an ID and insert it in the
+ * proper location.
+ */
+ @Override
+ public void changeDirectories(Cursor cursor) {
+ super.changeDirectories(cursor);
+ if (getDirectorySearchMode() == DirectoryListLoader.SEARCH_MODE_NONE) {
+ return;
+ }
+ final int numExtendedDirectories = mExtendedDirectories.size();
+ if (getPartitionCount() == cursor.getCount() + numExtendedDirectories) {
+ // already added all directories;
+ return;
+ }
+ //
+ mFirstExtendedDirectoryId = Long.MAX_VALUE;
+ if (numExtendedDirectories > 0) {
+ // The Directory.LOCAL_INVISIBLE is not in the cursor but we can't reuse it's
+ // "special" ID.
+ long maxId = Directory.LOCAL_INVISIBLE;
+ int insertIndex = 0;
+ for (int i = 0, n = getPartitionCount(); i < n; i++) {
+ final DirectoryPartition partition = (DirectoryPartition) getPartition(i);
+ final long id = partition.getDirectoryId();
+ if (id > maxId) {
+ maxId = id;
+ }
+ if (!DirectoryCompat.isRemoteDirectoryId(id)) {
+ // assuming remote directories come after local, we will end up with the index
+ // where we should insert extended directories. This also works if there are no
+ // remote directories at all.
+ insertIndex = i + 1;
+ }
+ }
+ // Extended directories ID's cannot collide with base directories
+ mFirstExtendedDirectoryId = maxId + 1;
+ for (int i = 0; i < numExtendedDirectories; i++) {
+ final long id = mFirstExtendedDirectoryId + i;
+ final DirectoryPartition directory = mExtendedDirectories.get(i);
+ if (getPartitionByDirectoryId(id) == -1) {
+ addPartition(insertIndex, directory);
+ directory.setDirectoryId(id);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected Uri getContactUri(int partitionIndex, Cursor cursor,
+ int contactIdColumn, int lookUpKeyColumn) {
+ final DirectoryPartition directory = (DirectoryPartition) getPartition(partitionIndex);
+ final long directoryId = directory.getDirectoryId();
+ if (!isExtendedDirectory(directoryId)) {
+ return super.getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn);
+ }
+ return Contacts.CONTENT_LOOKUP_URI.buildUpon()
+ .appendPath(Constants.LOOKUP_URI_ENCODED)
+ .appendQueryParameter(Directory.DISPLAY_NAME, directory.getLabel())
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId))
+ .encodedFragment(cursor.getString(lookUpKeyColumn))
+ .build();
+ }
+
+ public Listener getListener() {
+ return mListener;
+ }
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+}
diff --git a/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java b/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java
new file mode 100644
index 0000000..3b7ed6b
--- /dev/null
+++ b/src/com/android/contacts/common/list/PhoneNumberPickerFragment.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.Intent;
+import android.content.Loader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener;
+import com.android.contactsbind.analytics.AnalyticsUtil;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Fragment containing a phone number list for picking.
+ */
+public class PhoneNumberPickerFragment extends ContactEntryListFragment<ContactEntryListAdapter>
+ implements OnShortcutIntentCreatedListener, PhoneNumberListAdapter.Listener {
+ private static final String TAG = PhoneNumberPickerFragment.class.getSimpleName();
+
+ private static final String KEY_SHORTCUT_ACTION = "shortcutAction";
+
+ private OnPhoneNumberPickerActionListener mListener;
+ private String mShortcutAction;
+
+ private ContactListFilter mFilter;
+
+ private static final String KEY_FILTER = "filter";
+
+ /** true if the loader has started at least once. */
+ private boolean mLoaderStarted;
+
+ private boolean mUseCallableUri;
+
+ private ContactListItemView.PhotoPosition mPhotoPosition =
+ ContactListItemView.getDefaultPhotoPosition(false /* normal/non opposite */);
+
+ /**
+ * Handles a click on the video call icon for a row in the list.
+ *
+ * @param position The position in the list where the click ocurred.
+ */
+ @Override
+ public void onVideoCallIconClicked(int position) {
+ callNumber(position, true /* isVideoCall */);
+ }
+
+ public PhoneNumberPickerFragment() {
+ setQuickContactEnabled(false);
+ setPhotoLoaderEnabled(true);
+ setSectionHeaderDisplayEnabled(true);
+ setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE);
+
+ // Show nothing instead of letting caller Activity show something.
+ setHasOptionsMenu(true);
+ }
+
+ public void setDirectorySearchEnabled(boolean flag) {
+ setDirectorySearchMode(flag ? DirectoryListLoader.SEARCH_MODE_DEFAULT
+ : DirectoryListLoader.SEARCH_MODE_NONE);
+ }
+
+ public void setOnPhoneNumberPickerActionListener(OnPhoneNumberPickerActionListener listener) {
+ this.mListener = listener;
+ }
+
+ public OnPhoneNumberPickerActionListener getOnPhoneNumberPickerListener() {
+ return mListener;
+ }
+
+ @Override
+ protected void onCreateView(LayoutInflater inflater, ViewGroup container) {
+ super.onCreateView(inflater, container);
+
+ setVisibleScrollbarEnabled(getVisibleScrollbarEnabled());
+ }
+
+ protected boolean getVisibleScrollbarEnabled() {
+ return true;
+ }
+
+ @Override
+ public void restoreSavedState(Bundle savedState) {
+ super.restoreSavedState(savedState);
+
+ if (savedState == null) {
+ return;
+ }
+
+ mFilter = savedState.getParcelable(KEY_FILTER);
+ mShortcutAction = savedState.getString(KEY_SHORTCUT_ACTION);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putParcelable(KEY_FILTER, mFilter);
+ outState.putString(KEY_SHORTCUT_ACTION, mShortcutAction);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int itemId = item.getItemId();
+ if (itemId == android.R.id.home) { // See ActionBar#setDisplayHomeAsUpEnabled()
+ if (mListener != null) {
+ mListener.onHomeInActionBarSelected();
+ }
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /**
+ * @param shortcutAction either {@link Intent#ACTION_CALL} or
+ * {@link Intent#ACTION_SENDTO} or null.
+ */
+ public void setShortcutAction(String shortcutAction) {
+ this.mShortcutAction = shortcutAction;
+ }
+
+ @Override
+ protected void onItemClick(int position, long id) {
+ callNumber(position, false /* isVideoCall */);
+ }
+
+ /**
+ * Initiates a call to the number at the specified position.
+ *
+ * @param position The position.
+ * @param isVideoCall {@code true} if the call should be initiated as a video call,
+ * {@code false} otherwise.
+ */
+ private void callNumber(int position, boolean isVideoCall) {
+ final Uri phoneUri = getPhoneUri(position);
+
+ if (phoneUri != null) {
+ pickPhoneNumber(phoneUri, isVideoCall);
+ } else {
+ final String number = getPhoneNumber(position);
+ if (!TextUtils.isEmpty(number)) {
+ cacheContactInfo(position);
+ mListener.onPickPhoneNumber(number, isVideoCall,
+ getCallInitiationType(true /* isRemoteDirectory */));
+ } else {
+ Log.w(TAG, "Item at " + position + " was clicked before"
+ + " adapter is ready. Ignoring");
+ }
+ }
+
+ // Get the lookup key and track any analytics
+ final String lookupKey = getLookupKey(position);
+ if (!TextUtils.isEmpty(lookupKey)) {
+ maybeTrackAnalytics(lookupKey);
+ }
+ }
+
+ protected void cacheContactInfo(int position) {
+ // Not implemented. Hook for child classes
+ }
+
+ protected String getPhoneNumber(int position) {
+ final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter();
+ return adapter.getPhoneNumber(position);
+ }
+
+ protected Uri getPhoneUri(int position) {
+ final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter();
+ return adapter.getDataUri(position);
+ }
+
+ protected String getLookupKey(int position) {
+ final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter();
+ return adapter.getLookupKey(position);
+ }
+
+ @Override
+ protected void startLoading() {
+ mLoaderStarted = true;
+ super.startLoading();
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ super.onLoadFinished(loader, data);
+
+ // disable scroll bar if there is no data
+ setVisibleScrollbarEnabled(data != null && !data.isClosed() && data.getCount() > 0);
+ }
+
+ public void setUseCallableUri(boolean useCallableUri) {
+ mUseCallableUri = useCallableUri;
+ }
+
+ public boolean usesCallableUri() {
+ return mUseCallableUri;
+ }
+
+ @Override
+ protected ContactEntryListAdapter createListAdapter() {
+ PhoneNumberListAdapter adapter = new PhoneNumberListAdapter(getActivity());
+ adapter.setDisplayPhotos(true);
+ adapter.setUseCallableUri(mUseCallableUri);
+ return adapter;
+ }
+
+ @Override
+ protected void configureAdapter() {
+ super.configureAdapter();
+
+ final ContactEntryListAdapter adapter = getAdapter();
+ if (adapter == null) {
+ return;
+ }
+
+ if (!isSearchMode() && mFilter != null) {
+ adapter.setFilter(mFilter);
+ }
+
+ setPhotoPosition(adapter);
+ }
+
+ protected void setPhotoPosition(ContactEntryListAdapter adapter) {
+ ((PhoneNumberListAdapter) adapter).setPhotoPosition(mPhotoPosition);
+ }
+
+ @Override
+ protected View inflateView(LayoutInflater inflater, ViewGroup container) {
+ return inflater.inflate(R.layout.contact_list_content, null);
+ }
+
+ public void pickPhoneNumber(Uri uri, boolean isVideoCall) {
+ if (mShortcutAction == null) {
+ mListener.onPickDataUri(uri, isVideoCall,
+ getCallInitiationType(false /* isRemoteDirectory */));
+ } else {
+ startPhoneNumberShortcutIntent(uri, isVideoCall);
+ }
+ }
+
+ protected void startPhoneNumberShortcutIntent(Uri uri, boolean isVideoCall) {
+ ShortcutIntentBuilder builder = new ShortcutIntentBuilder(getActivity(), this);
+ builder.createPhoneNumberShortcutIntent(uri, mShortcutAction);
+ }
+
+ @Override
+ public void onShortcutIntentCreated(Uri uri, Intent shortcutIntent) {
+ mListener.onShortcutIntentCreated(shortcutIntent);
+ }
+
+ @Override
+ public void onPickerResult(Intent data) {
+ mListener.onPickDataUri(data.getData(), false /* isVideoCall */,
+ getCallInitiationType(false /* isRemoteDirectory */));
+ }
+
+ public void setFilter(ContactListFilter filter) {
+ if ((mFilter == null && filter == null) ||
+ (mFilter != null && mFilter.equals(filter))) {
+ return;
+ }
+
+ mFilter = filter;
+ if (mLoaderStarted) {
+ reloadData();
+ }
+ }
+
+ public void setPhotoPosition(ContactListItemView.PhotoPosition photoPosition) {
+ mPhotoPosition = photoPosition;
+
+ final PhoneNumberListAdapter adapter = (PhoneNumberListAdapter) getAdapter();
+ if (adapter != null) {
+ adapter.setPhotoPosition(photoPosition);
+ }
+ }
+
+ /**
+ * @param isRemoteDirectory {@code true} if the call was initiated using a contact/phone number
+ * not in the local contacts database
+ */
+ protected int getCallInitiationType(boolean isRemoteDirectory) {
+ return OnPhoneNumberPickerActionListener.CALL_INITIATION_UNKNOWN;
+ }
+
+ /**
+ * Where a lookup key contains analytic event information, logs the associated analytics event.
+ *
+ * @param lookupKey The lookup key JSON object.
+ */
+ private void maybeTrackAnalytics(String lookupKey) {
+ try {
+ JSONObject json = new JSONObject(lookupKey);
+
+ String analyticsCategory = json.getString(
+ PhoneNumberListAdapter.PhoneQuery.ANALYTICS_CATEGORY);
+ String analyticsAction = json.getString(
+ PhoneNumberListAdapter.PhoneQuery.ANALYTICS_ACTION);
+ String analyticsValue = json.getString(
+ PhoneNumberListAdapter.PhoneQuery.ANALYTICS_VALUE);
+
+ if (TextUtils.isEmpty(analyticsCategory) || TextUtils.isEmpty(analyticsAction) ||
+ TextUtils.isEmpty(analyticsValue)) {
+ return;
+ }
+
+ // Assume that the analytic value being tracked could be a float value, but just cast
+ // to a long so that the analytic server can handle it.
+ long value;
+ try {
+ float floatValue = Float.parseFloat(analyticsValue);
+ value = (long) floatValue;
+ } catch (NumberFormatException nfe) {
+ return;
+ }
+
+ AnalyticsUtil.sendEvent(getActivity().getApplication(), analyticsCategory,
+ analyticsAction, "" /* label */, value);
+ } catch (JSONException e) {
+ // Not an error; just a lookup key that doesn't have the right information.
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/list/PinnedHeaderListAdapter.java b/src/com/android/contacts/common/list/PinnedHeaderListAdapter.java
new file mode 100644
index 0000000..72f3f19
--- /dev/null
+++ b/src/com/android/contacts/common/list/PinnedHeaderListAdapter.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.common.widget.CompositeCursorAdapter;
+
+/**
+ * A subclass of {@link CompositeCursorAdapter} that manages pinned partition headers.
+ */
+public abstract class PinnedHeaderListAdapter extends CompositeCursorAdapter
+ implements PinnedHeaderListView.PinnedHeaderAdapter {
+
+ public static final int PARTITION_HEADER_TYPE = 0;
+
+ private boolean mPinnedPartitionHeadersEnabled;
+ private boolean mHeaderVisibility[];
+
+ public PinnedHeaderListAdapter(Context context) {
+ super(context);
+ }
+
+ public PinnedHeaderListAdapter(Context context, int initialCapacity) {
+ super(context, initialCapacity);
+ }
+
+ public boolean getPinnedPartitionHeadersEnabled() {
+ return mPinnedPartitionHeadersEnabled;
+ }
+
+ public void setPinnedPartitionHeadersEnabled(boolean flag) {
+ this.mPinnedPartitionHeadersEnabled = flag;
+ }
+
+ @Override
+ public int getPinnedHeaderCount() {
+ if (mPinnedPartitionHeadersEnabled) {
+ return getPartitionCount();
+ } else {
+ return 0;
+ }
+ }
+
+ protected boolean isPinnedPartitionHeaderVisible(int partition) {
+ return getPinnedPartitionHeadersEnabled() && hasHeader(partition)
+ && !isPartitionEmpty(partition);
+ }
+
+ /**
+ * The default implementation creates the same type of view as a normal
+ * partition header.
+ */
+ @Override
+ public View getPinnedHeaderView(int partition, View convertView, ViewGroup parent) {
+ if (hasHeader(partition)) {
+ View view = null;
+ if (convertView != null) {
+ Integer headerType = (Integer)convertView.getTag();
+ if (headerType != null && headerType == PARTITION_HEADER_TYPE) {
+ view = convertView;
+ }
+ }
+ if (view == null) {
+ view = newHeaderView(getContext(), partition, null, parent);
+ view.setTag(PARTITION_HEADER_TYPE);
+ view.setFocusable(false);
+ view.setEnabled(false);
+ }
+ bindHeaderView(view, partition, getCursor(partition));
+ view.setLayoutDirection(parent.getLayoutDirection());
+ return view;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void configurePinnedHeaders(PinnedHeaderListView listView) {
+ if (!getPinnedPartitionHeadersEnabled()) {
+ return;
+ }
+
+ int size = getPartitionCount();
+
+ // Cache visibility bits, because we will need them several times later on
+ if (mHeaderVisibility == null || mHeaderVisibility.length != size) {
+ mHeaderVisibility = new boolean[size];
+ }
+ for (int i = 0; i < size; i++) {
+ boolean visible = isPinnedPartitionHeaderVisible(i);
+ mHeaderVisibility[i] = visible;
+ if (!visible) {
+ listView.setHeaderInvisible(i, true);
+ }
+ }
+
+ int headerViewsCount = listView.getHeaderViewsCount();
+
+ // Starting at the top, find and pin headers for partitions preceding the visible one(s)
+ int maxTopHeader = -1;
+ int topHeaderHeight = 0;
+ for (int i = 0; i < size; i++) {
+ if (mHeaderVisibility[i]) {
+ int position = listView.getPositionAt(topHeaderHeight) - headerViewsCount;
+ int partition = getPartitionForPosition(position);
+ if (i > partition) {
+ break;
+ }
+
+ listView.setHeaderPinnedAtTop(i, topHeaderHeight, false);
+ topHeaderHeight += listView.getPinnedHeaderHeight(i);
+ maxTopHeader = i;
+ }
+ }
+
+ // Starting at the bottom, find and pin headers for partitions following the visible one(s)
+ int maxBottomHeader = size;
+ int bottomHeaderHeight = 0;
+ int listHeight = listView.getHeight();
+ for (int i = size; --i > maxTopHeader;) {
+ if (mHeaderVisibility[i]) {
+ int position = listView.getPositionAt(listHeight - bottomHeaderHeight)
+ - headerViewsCount;
+ if (position < 0) {
+ break;
+ }
+
+ int partition = getPartitionForPosition(position - 1);
+ if (partition == -1 || i <= partition) {
+ break;
+ }
+
+ int height = listView.getPinnedHeaderHeight(i);
+ bottomHeaderHeight += height;
+
+ listView.setHeaderPinnedAtBottom(i, listHeight - bottomHeaderHeight, false);
+ maxBottomHeader = i;
+ }
+ }
+
+ // Headers in between the top-pinned and bottom-pinned should be hidden
+ for (int i = maxTopHeader + 1; i < maxBottomHeader; i++) {
+ if (mHeaderVisibility[i]) {
+ listView.setHeaderInvisible(i, isPartitionEmpty(i));
+ }
+ }
+ }
+
+ @Override
+ public int getScrollPositionForHeader(int viewIndex) {
+ return getPositionForPartition(viewIndex);
+ }
+}
diff --git a/src/com/android/contacts/common/list/PinnedHeaderListView.java b/src/com/android/contacts/common/list/PinnedHeaderListView.java
new file mode 100644
index 0000000..45ce4b3
--- /dev/null
+++ b/src/com/android/contacts/common/list/PinnedHeaderListView.java
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.util.ViewUtil;
+
+/**
+ * A ListView that maintains a header pinned at the top of the list. The
+ * pinned header can be pushed up and dissolved as needed.
+ */
+public class PinnedHeaderListView extends AutoScrollListView
+ implements OnScrollListener, OnItemSelectedListener {
+
+ /**
+ * Adapter interface. The list adapter must implement this interface.
+ */
+ public interface PinnedHeaderAdapter {
+
+ /**
+ * Returns the overall number of pinned headers, visible or not.
+ */
+ int getPinnedHeaderCount();
+
+ /**
+ * Creates or updates the pinned header view.
+ */
+ View getPinnedHeaderView(int viewIndex, View convertView, ViewGroup parent);
+
+ /**
+ * Configures the pinned headers to match the visible list items. The
+ * adapter should call {@link PinnedHeaderListView#setHeaderPinnedAtTop},
+ * {@link PinnedHeaderListView#setHeaderPinnedAtBottom},
+ * {@link PinnedHeaderListView#setFadingHeader} or
+ * {@link PinnedHeaderListView#setHeaderInvisible}, for each header that
+ * needs to change its position or visibility.
+ */
+ void configurePinnedHeaders(PinnedHeaderListView listView);
+
+ /**
+ * Returns the list position to scroll to if the pinned header is touched.
+ * Return -1 if the list does not need to be scrolled.
+ */
+ int getScrollPositionForHeader(int viewIndex);
+ }
+
+ private static final int MAX_ALPHA = 255;
+ private static final int TOP = 0;
+ private static final int BOTTOM = 1;
+ private static final int FADING = 2;
+
+ private static final int DEFAULT_ANIMATION_DURATION = 20;
+
+ private static final int DEFAULT_SMOOTH_SCROLL_DURATION = 100;
+
+ private static final class PinnedHeader {
+ View view;
+ boolean visible;
+ int y;
+ int height;
+ int alpha;
+ int state;
+
+ boolean animating;
+ boolean targetVisible;
+ int sourceY;
+ int targetY;
+ long targetTime;
+ }
+
+ private PinnedHeaderAdapter mAdapter;
+ private int mSize;
+ private PinnedHeader[] mHeaders;
+ private RectF mBounds = new RectF();
+ private OnScrollListener mOnScrollListener;
+ private OnItemSelectedListener mOnItemSelectedListener;
+ private int mScrollState;
+
+ private boolean mScrollToSectionOnHeaderTouch = false;
+ private boolean mHeaderTouched = false;
+
+ private int mAnimationDuration = DEFAULT_ANIMATION_DURATION;
+ private boolean mAnimating;
+ private long mAnimationTargetTime;
+ private int mHeaderPaddingStart;
+ private int mHeaderWidth;
+
+ public PinnedHeaderListView(Context context) {
+ this(context, null, android.R.attr.listViewStyle);
+ }
+
+ public PinnedHeaderListView(Context context, AttributeSet attrs) {
+ this(context, attrs, android.R.attr.listViewStyle);
+ }
+
+ public PinnedHeaderListView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ super.setOnScrollListener(this);
+ super.setOnItemSelectedListener(this);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ mHeaderPaddingStart = getPaddingStart();
+ mHeaderWidth = r - l - mHeaderPaddingStart - getPaddingEnd();
+ }
+
+ @Override
+ public void setAdapter(ListAdapter adapter) {
+ mAdapter = (PinnedHeaderAdapter)adapter;
+ super.setAdapter(adapter);
+ }
+
+ @Override
+ public void setOnScrollListener(OnScrollListener onScrollListener) {
+ mOnScrollListener = onScrollListener;
+ super.setOnScrollListener(this);
+ }
+
+ @Override
+ public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+ mOnItemSelectedListener = listener;
+ super.setOnItemSelectedListener(this);
+ }
+
+ public void setScrollToSectionOnHeaderTouch(boolean value) {
+ mScrollToSectionOnHeaderTouch = value;
+ }
+
+ @Override
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+ int totalItemCount) {
+ if (mAdapter != null) {
+ int count = mAdapter.getPinnedHeaderCount();
+ if (count != mSize) {
+ mSize = count;
+ if (mHeaders == null) {
+ mHeaders = new PinnedHeader[mSize];
+ } else if (mHeaders.length < mSize) {
+ PinnedHeader[] headers = mHeaders;
+ mHeaders = new PinnedHeader[mSize];
+ System.arraycopy(headers, 0, mHeaders, 0, headers.length);
+ }
+ }
+
+ for (int i = 0; i < mSize; i++) {
+ if (mHeaders[i] == null) {
+ mHeaders[i] = new PinnedHeader();
+ }
+ mHeaders[i].view = mAdapter.getPinnedHeaderView(i, mHeaders[i].view, this);
+ }
+
+ mAnimationTargetTime = System.currentTimeMillis() + mAnimationDuration;
+ mAdapter.configurePinnedHeaders(this);
+ invalidateIfAnimating();
+ }
+ if (mOnScrollListener != null) {
+ mOnScrollListener.onScroll(this, firstVisibleItem, visibleItemCount, totalItemCount);
+ }
+ }
+
+ @Override
+ protected float getTopFadingEdgeStrength() {
+ // Disable vertical fading at the top when the pinned header is present
+ return mSize > 0 ? 0 : super.getTopFadingEdgeStrength();
+ }
+
+ @Override
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ mScrollState = scrollState;
+ if (mOnScrollListener != null) {
+ mOnScrollListener.onScrollStateChanged(this, scrollState);
+ }
+ }
+
+ /**
+ * Ensures that the selected item is positioned below the top-pinned headers
+ * and above the bottom-pinned ones.
+ */
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ int height = getHeight();
+
+ int windowTop = 0;
+ int windowBottom = height;
+
+ for (int i = 0; i < mSize; i++) {
+ PinnedHeader header = mHeaders[i];
+ if (header.visible) {
+ if (header.state == TOP) {
+ windowTop = header.y + header.height;
+ } else if (header.state == BOTTOM) {
+ windowBottom = header.y;
+ break;
+ }
+ }
+ }
+
+ View selectedView = getSelectedView();
+ if (selectedView != null) {
+ if (selectedView.getTop() < windowTop) {
+ setSelectionFromTop(position, windowTop);
+ } else if (selectedView.getBottom() > windowBottom) {
+ setSelectionFromTop(position, windowBottom - selectedView.getHeight());
+ }
+ }
+
+ if (mOnItemSelectedListener != null) {
+ mOnItemSelectedListener.onItemSelected(parent, view, position, id);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ if (mOnItemSelectedListener != null) {
+ mOnItemSelectedListener.onNothingSelected(parent);
+ }
+ }
+
+ public int getPinnedHeaderHeight(int viewIndex) {
+ ensurePinnedHeaderLayout(viewIndex);
+ return mHeaders[viewIndex].view.getHeight();
+ }
+
+ /**
+ * Set header to be pinned at the top.
+ *
+ * @param viewIndex index of the header view
+ * @param y is position of the header in pixels.
+ * @param animate true if the transition to the new coordinate should be animated
+ */
+ public void setHeaderPinnedAtTop(int viewIndex, int y, boolean animate) {
+ ensurePinnedHeaderLayout(viewIndex);
+ PinnedHeader header = mHeaders[viewIndex];
+ header.visible = true;
+ header.y = y;
+ header.state = TOP;
+
+ // TODO perhaps we should animate at the top as well
+ header.animating = false;
+ }
+
+ /**
+ * Set header to be pinned at the bottom.
+ *
+ * @param viewIndex index of the header view
+ * @param y is position of the header in pixels.
+ * @param animate true if the transition to the new coordinate should be animated
+ */
+ public void setHeaderPinnedAtBottom(int viewIndex, int y, boolean animate) {
+ ensurePinnedHeaderLayout(viewIndex);
+ PinnedHeader header = mHeaders[viewIndex];
+ header.state = BOTTOM;
+ if (header.animating) {
+ header.targetTime = mAnimationTargetTime;
+ header.sourceY = header.y;
+ header.targetY = y;
+ } else if (animate && (header.y != y || !header.visible)) {
+ if (header.visible) {
+ header.sourceY = header.y;
+ } else {
+ header.visible = true;
+ header.sourceY = y + header.height;
+ }
+ header.animating = true;
+ header.targetVisible = true;
+ header.targetTime = mAnimationTargetTime;
+ header.targetY = y;
+ } else {
+ header.visible = true;
+ header.y = y;
+ }
+ }
+
+ /**
+ * Set header to be pinned at the top of the first visible item.
+ *
+ * @param viewIndex index of the header view
+ * @param position is position of the header in pixels.
+ */
+ public void setFadingHeader(int viewIndex, int position, boolean fade) {
+ ensurePinnedHeaderLayout(viewIndex);
+
+ View child = getChildAt(position - getFirstVisiblePosition());
+ if (child == null) return;
+
+ PinnedHeader header = mHeaders[viewIndex];
+ // Hide header when it's a star.
+ // TODO: try showing the view even when it's a star;
+ // if we have to hide the star view, then try hiding it in some higher layer.
+ header.visible = !TextUtils.equals(
+ ((TextView) header.view).getText(), getContext().getString(R.string.star_sign));
+ header.state = FADING;
+ header.alpha = MAX_ALPHA;
+ header.animating = false;
+
+ int top = getTotalTopPinnedHeaderHeight();
+ header.y = top;
+ if (fade) {
+ int bottom = child.getBottom() - top;
+ int headerHeight = header.height;
+ if (bottom < headerHeight) {
+ int portion = bottom - headerHeight;
+ header.alpha = MAX_ALPHA * (headerHeight + portion) / headerHeight;
+ header.y = top + portion;
+ }
+ }
+ }
+
+ /**
+ * Makes header invisible.
+ *
+ * @param viewIndex index of the header view
+ * @param animate true if the transition to the new coordinate should be animated
+ */
+ public void setHeaderInvisible(int viewIndex, boolean animate) {
+ PinnedHeader header = mHeaders[viewIndex];
+ if (header.visible && (animate || header.animating) && header.state == BOTTOM) {
+ header.sourceY = header.y;
+ if (!header.animating) {
+ header.visible = true;
+ header.targetY = getBottom() + header.height;
+ }
+ header.animating = true;
+ header.targetTime = mAnimationTargetTime;
+ header.targetVisible = false;
+ } else {
+ header.visible = false;
+ }
+ }
+
+ private void ensurePinnedHeaderLayout(int viewIndex) {
+ View view = mHeaders[viewIndex].view;
+ if (view.isLayoutRequested()) {
+ ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
+ int widthSpec;
+ int heightSpec;
+
+ if (layoutParams != null && layoutParams.width > 0) {
+ widthSpec = View.MeasureSpec
+ .makeMeasureSpec(layoutParams.width, View.MeasureSpec.EXACTLY);
+ } else {
+ widthSpec = View.MeasureSpec
+ .makeMeasureSpec(mHeaderWidth, View.MeasureSpec.EXACTLY);
+ }
+
+ if (layoutParams != null && layoutParams.height > 0) {
+ heightSpec = View.MeasureSpec
+ .makeMeasureSpec(layoutParams.height, View.MeasureSpec.EXACTLY);
+ } else {
+ heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+ }
+ view.measure(widthSpec, heightSpec);
+ int height = view.getMeasuredHeight();
+ mHeaders[viewIndex].height = height;
+ view.layout(0, 0, view.getMeasuredWidth(), height);
+ }
+ }
+
+ /**
+ * Returns the sum of heights of headers pinned to the top.
+ */
+ public int getTotalTopPinnedHeaderHeight() {
+ for (int i = mSize; --i >= 0;) {
+ PinnedHeader header = mHeaders[i];
+ if (header.visible && header.state == TOP) {
+ return header.y + header.height;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the list item position at the specified y coordinate.
+ */
+ public int getPositionAt(int y) {
+ do {
+ int position = pointToPosition(getPaddingLeft() + 1, y);
+ if (position != -1) {
+ return position;
+ }
+ // If position == -1, we must have hit a separator. Let's examine
+ // a nearby pixel
+ y--;
+ } while (y > 0);
+ return 0;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ mHeaderTouched = false;
+ if (super.onInterceptTouchEvent(ev)) {
+ return true;
+ }
+
+ if (mScrollState == SCROLL_STATE_IDLE) {
+ final int y = (int)ev.getY();
+ final int x = (int)ev.getX();
+ for (int i = mSize; --i >= 0;) {
+ PinnedHeader header = mHeaders[i];
+ final int padding = ViewUtil.isViewLayoutRtl(this) ?
+ getWidth() - mHeaderPaddingStart - header.view.getWidth() :
+ mHeaderPaddingStart;
+ if (header.visible && header.y <= y && header.y + header.height > y &&
+ x >= padding && padding + header.view.getWidth() >= x) {
+ mHeaderTouched = true;
+ if (mScrollToSectionOnHeaderTouch &&
+ ev.getAction() == MotionEvent.ACTION_DOWN) {
+ return smoothScrollToPartition(i);
+ } else {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (mHeaderTouched) {
+ if (ev.getAction() == MotionEvent.ACTION_UP) {
+ mHeaderTouched = false;
+ }
+ return true;
+ }
+ return super.onTouchEvent(ev);
+ }
+
+ private boolean smoothScrollToPartition(int partition) {
+ if (mAdapter == null) {
+ return false;
+ }
+ final int position = mAdapter.getScrollPositionForHeader(partition);
+ if (position == -1) {
+ return false;
+ }
+
+ int offset = 0;
+ for (int i = 0; i < partition; i++) {
+ PinnedHeader header = mHeaders[i];
+ if (header.visible) {
+ offset += header.height;
+ }
+ }
+ smoothScrollToPositionFromTop(position + getHeaderViewsCount(), offset,
+ DEFAULT_SMOOTH_SCROLL_DURATION);
+ return true;
+ }
+
+ private void invalidateIfAnimating() {
+ mAnimating = false;
+ for (int i = 0; i < mSize; i++) {
+ if (mHeaders[i].animating) {
+ mAnimating = true;
+ invalidate();
+ return;
+ }
+ }
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ long currentTime = mAnimating ? System.currentTimeMillis() : 0;
+
+ int top = 0;
+ int right = 0;
+ int bottom = getBottom();
+ boolean hasVisibleHeaders = false;
+ for (int i = 0; i < mSize; i++) {
+ PinnedHeader header = mHeaders[i];
+ if (header.visible) {
+ hasVisibleHeaders = true;
+ if (header.state == BOTTOM && header.y < bottom) {
+ bottom = header.y;
+ } else if (header.state == TOP || header.state == FADING) {
+ int newTop = header.y + header.height;
+ if (newTop > top) {
+ top = newTop;
+ }
+ }
+ }
+ }
+
+ if (hasVisibleHeaders) {
+ canvas.save();
+ }
+
+ super.dispatchDraw(canvas);
+
+ if (hasVisibleHeaders) {
+ canvas.restore();
+
+ // If the first item is visible and if it has a positive top that is greater than the
+ // first header's assigned y-value, use that for the first header's y value. This way,
+ // the header inherits any padding applied to the list view.
+ if (mSize > 0 && getFirstVisiblePosition() == 0) {
+ View firstChild = getChildAt(0);
+ PinnedHeader firstHeader = mHeaders[0];
+
+ if (firstHeader != null) {
+ int firstHeaderTop = firstChild != null ? firstChild.getTop() : 0;
+ firstHeader.y = Math.max(firstHeader.y, firstHeaderTop);
+ }
+ }
+
+ // First draw top headers, then the bottom ones to handle the Z axis correctly
+ for (int i = mSize; --i >= 0;) {
+ PinnedHeader header = mHeaders[i];
+ if (header.visible && (header.state == TOP || header.state == FADING)) {
+ drawHeader(canvas, header, currentTime);
+ }
+ }
+
+ for (int i = 0; i < mSize; i++) {
+ PinnedHeader header = mHeaders[i];
+ if (header.visible && header.state == BOTTOM) {
+ drawHeader(canvas, header, currentTime);
+ }
+ }
+ }
+
+ invalidateIfAnimating();
+ }
+
+ private void drawHeader(Canvas canvas, PinnedHeader header, long currentTime) {
+ if (header.animating) {
+ int timeLeft = (int)(header.targetTime - currentTime);
+ if (timeLeft <= 0) {
+ header.y = header.targetY;
+ header.visible = header.targetVisible;
+ header.animating = false;
+ } else {
+ header.y = header.targetY + (header.sourceY - header.targetY) * timeLeft
+ / mAnimationDuration;
+ }
+ }
+ if (header.visible) {
+ View view = header.view;
+ int saveCount = canvas.save();
+ int translateX = ViewUtil.isViewLayoutRtl(this) ?
+ getWidth() - mHeaderPaddingStart - view.getWidth() :
+ mHeaderPaddingStart;
+ canvas.translate(translateX, header.y);
+ if (header.state == FADING) {
+ mBounds.set(0, 0, view.getWidth(), view.getHeight());
+ canvas.saveLayerAlpha(mBounds, header.alpha, Canvas.ALL_SAVE_FLAG);
+ }
+ view.draw(canvas);
+ canvas.restoreToCount(saveCount);
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/list/ProviderStatusWatcher.java b/src/com/android/contacts/common/list/ProviderStatusWatcher.java
new file mode 100644
index 0000000..3e8e2eb
--- /dev/null
+++ b/src/com/android/contacts/common/list/ProviderStatusWatcher.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2012 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.common.list;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.provider.ContactsContract.ProviderStatus;
+import android.util.Log;
+
+import com.android.contacts.common.compat.ProviderStatusCompat;
+
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+
+/**
+ * A singleton that keeps track of the last known provider status.
+ *
+ * All methods must be called on the UI thread unless noted otherwise.
+ *
+ * All members must be set on the UI thread unless noted otherwise.
+ */
+public class ProviderStatusWatcher extends ContentObserver {
+ private static final String TAG = "ProviderStatusWatcher";
+ private static final boolean DEBUG = false;
+
+ /**
+ * Callback interface invoked when the provider status changes.
+ */
+ public interface ProviderStatusListener {
+ public void onProviderStatusChange();
+ }
+
+ private static final String[] PROJECTION = new String[] {
+ ProviderStatus.STATUS
+ };
+
+ /**
+ * We'll wait for this amount of time on the UI thread if the load hasn't finished.
+ */
+ private static final int LOAD_WAIT_TIMEOUT_MS = 1000;
+
+ private static ProviderStatusWatcher sInstance;
+
+ private final Context mContext;
+ private final Handler mHandler = new Handler();
+
+ private final Object mSignal = new Object();
+
+ private int mStartRequestedCount;
+
+ private LoaderTask mLoaderTask;
+
+ /** Last known provider status. This can be changed on a worker thread.
+ * See {@link ProviderStatus#STATUS} */
+ private Integer mProviderStatus;
+
+ private final ArrayList<ProviderStatusListener> mListeners = Lists.newArrayList();
+
+ private final Runnable mStartLoadingRunnable = new Runnable() {
+ @Override
+ public void run() {
+ startLoading();
+ }
+ };
+
+ /**
+ * Returns the singleton instance.
+ */
+ public synchronized static ProviderStatusWatcher getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new ProviderStatusWatcher(context);
+ }
+ return sInstance;
+ }
+
+ private ProviderStatusWatcher(Context context) {
+ super(null);
+ mContext = context;
+ }
+
+ /** Add a listener. */
+ public void addListener(ProviderStatusListener listener) {
+ mListeners.add(listener);
+ }
+
+ /** Remove a listener */
+ public void removeListener(ProviderStatusListener listener) {
+ mListeners.remove(listener);
+ }
+
+ private void notifyListeners() {
+ if (DEBUG) {
+ Log.d(TAG, "notifyListeners: " + mListeners.size());
+ }
+ if (isStarted()) {
+ for (ProviderStatusListener listener : mListeners) {
+ listener.onProviderStatusChange();
+ }
+ }
+ }
+
+ private boolean isStarted() {
+ return mStartRequestedCount > 0;
+ }
+
+ /**
+ * Starts watching the provider status. {@link #start()} and {@link #stop()} calls can be
+ * nested.
+ */
+ public void start() {
+ if (++mStartRequestedCount == 1) {
+ mContext.getContentResolver()
+ .registerContentObserver(ProviderStatus.CONTENT_URI, false, this);
+ startLoading();
+
+ if (DEBUG) {
+ Log.d(TAG, "Start observing");
+ }
+ }
+ }
+
+ /**
+ * Stops watching the provider status.
+ */
+ public void stop() {
+ if (!isStarted()) {
+ Log.e(TAG, "Already stopped");
+ return;
+ }
+ if (--mStartRequestedCount == 0) {
+
+ mHandler.removeCallbacks(mStartLoadingRunnable);
+
+ mContext.getContentResolver().unregisterContentObserver(this);
+ if (DEBUG) {
+ Log.d(TAG, "Stop observing");
+ }
+ }
+ }
+
+ /**
+ * @return last known provider status.
+ *
+ * If this method is called when we haven't started the status query or the query is still in
+ * progress, it will start a query in a worker thread if necessary, and *wait for the result*.
+ *
+ * This means this method is essentially a blocking {@link ProviderStatus#CONTENT_URI} query.
+ * This URI is not backed by the file system, so is usually fast enough to perform on the main
+ * thread, but in extreme cases (when the system takes a while to bring up the contacts
+ * provider?) this may still cause ANRs.
+ *
+ * In order to avoid that, if we can't load the status within {@link #LOAD_WAIT_TIMEOUT_MS},
+ * we'll give up and just returns {@link ProviderStatusCompat#STATUS_BUSY} in order to unblock
+ * the UI thread. The actual result will be delivered later via {@link ProviderStatusListener}.
+ * (If {@link ProviderStatusCompat#STATUS_BUSY} is returned, the app (should) shows an according
+ * message, like "contacts are being updated".)
+ */
+ public int getProviderStatus() {
+ waitForLoaded();
+
+ if (mProviderStatus == null) {
+ return ProviderStatusCompat.STATUS_BUSY;
+ }
+
+ return mProviderStatus;
+ }
+
+ private void waitForLoaded() {
+ if (mProviderStatus == null) {
+ if (mLoaderTask == null) {
+ // For some reason the loader couldn't load the status. Let's start it again.
+ startLoading();
+ }
+ synchronized (mSignal) {
+ try {
+ mSignal.wait(LOAD_WAIT_TIMEOUT_MS);
+ } catch (InterruptedException ignore) {
+ }
+ }
+ }
+ }
+
+ private void startLoading() {
+ if (mLoaderTask != null) {
+ return; // Task already running.
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "Start loading");
+ }
+
+ mLoaderTask = new LoaderTask();
+ mLoaderTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ private class LoaderTask extends AsyncTask<Void, Void, Boolean> {
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ try {
+ Cursor cursor = mContext.getContentResolver().query(ProviderStatus.CONTENT_URI,
+ PROJECTION, null, null, null);
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ // Note here we can't just say "Status", as AsyncTask has the "Status"
+ // enum too.
+ mProviderStatus = cursor.getInt(0);
+ return true;
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ return false;
+ } finally {
+ synchronized (mSignal) {
+ mSignal.notifyAll();
+ }
+ }
+ }
+
+ @Override
+ protected void onCancelled(Boolean result) {
+ cleanUp();
+ }
+
+ @Override
+ protected void onPostExecute(Boolean loaded) {
+ cleanUp();
+ if (loaded != null && loaded) {
+ notifyListeners();
+ }
+ }
+
+ private void cleanUp() {
+ mLoaderTask = null;
+ }
+ }
+
+ /**
+ * Called when provider status may has changed.
+ *
+ * This method will be called on a worker thread by the framework.
+ */
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (!ProviderStatus.CONTENT_URI.equals(uri)) return;
+
+ // Provider status change is rare, so okay to log.
+ Log.i(TAG, "Provider status changed.");
+
+ mHandler.removeCallbacks(mStartLoadingRunnable); // Remove one in the queue, if any.
+ mHandler.post(mStartLoadingRunnable);
+ }
+}
diff --git a/src/com/android/contacts/common/list/ShortcutIntentBuilder.java b/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
new file mode 100644
index 0000000..f30a176
--- /dev/null
+++ b/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2010 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.common.list;
+
+import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.telecom.PhoneAccount;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.TextUtils.TruncateAt;
+
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+import com.android.contacts.common.R;
+
+/**
+ * Constructs shortcut intents.
+ */
+public class ShortcutIntentBuilder {
+
+ private static final String[] CONTACT_COLUMNS = {
+ Contacts.DISPLAY_NAME,
+ Contacts.PHOTO_ID,
+ Contacts.LOOKUP_KEY
+ };
+
+ private static final int CONTACT_DISPLAY_NAME_COLUMN_INDEX = 0;
+ private static final int CONTACT_PHOTO_ID_COLUMN_INDEX = 1;
+ private static final int CONTACT_LOOKUP_KEY_COLUMN_INDEX = 2;
+
+ private static final String[] PHONE_COLUMNS = {
+ Phone.DISPLAY_NAME,
+ Phone.PHOTO_ID,
+ Phone.NUMBER,
+ Phone.TYPE,
+ Phone.LABEL,
+ Phone.LOOKUP_KEY
+ };
+
+ private static final int PHONE_DISPLAY_NAME_COLUMN_INDEX = 0;
+ private static final int PHONE_PHOTO_ID_COLUMN_INDEX = 1;
+ private static final int PHONE_NUMBER_COLUMN_INDEX = 2;
+ private static final int PHONE_TYPE_COLUMN_INDEX = 3;
+ private static final int PHONE_LABEL_COLUMN_INDEX = 4;
+ private static final int PHONE_LOOKUP_KEY_COLUMN_INDEX = 5;
+
+ private static final String[] PHOTO_COLUMNS = {
+ Photo.PHOTO,
+ };
+
+ private static final int PHOTO_PHOTO_COLUMN_INDEX = 0;
+
+ private static final String PHOTO_SELECTION = Photo._ID + "=?";
+
+ private final OnShortcutIntentCreatedListener mListener;
+ private final Context mContext;
+ private int mIconSize;
+ private final int mIconDensity;
+ private final int mOverlayTextBackgroundColor;
+ private final Resources mResources;
+
+ /**
+ * This is a hidden API of the launcher in JellyBean that allows us to disable the animation
+ * that it would usually do, because it interferes with our own animation for QuickContact.
+ * This is needed since some versions of the launcher override the intent flags and therefore
+ * ignore Intent.FLAG_ACTIVITY_NO_ANIMATION.
+ */
+ public static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
+ "com.android.launcher.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
+
+ /**
+ * Listener interface.
+ */
+ public interface OnShortcutIntentCreatedListener {
+
+ /**
+ * Callback for shortcut intent creation.
+ *
+ * @param uri the original URI for which the shortcut intent has been
+ * created.
+ * @param shortcutIntent resulting shortcut intent.
+ */
+ void onShortcutIntentCreated(Uri uri, Intent shortcutIntent);
+ }
+
+ public ShortcutIntentBuilder(Context context, OnShortcutIntentCreatedListener listener) {
+ mContext = context;
+ mListener = listener;
+
+ mResources = context.getResources();
+ final ActivityManager am = (ActivityManager) context
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ mIconSize = mResources.getDimensionPixelSize(R.dimen.shortcut_icon_size);
+ if (mIconSize == 0) {
+ mIconSize = am.getLauncherLargeIconSize();
+ }
+ mIconDensity = am.getLauncherLargeIconDensity();
+ mOverlayTextBackgroundColor = mResources.getColor(R.color.shortcut_overlay_text_background);
+ }
+
+ public void createContactShortcutIntent(Uri contactUri) {
+ new ContactLoadingAsyncTask(contactUri).execute();
+ }
+
+ public void createPhoneNumberShortcutIntent(Uri dataUri, String shortcutAction) {
+ new PhoneNumberLoadingAsyncTask(dataUri, shortcutAction).execute();
+ }
+
+ /**
+ * An asynchronous task that loads name, photo and other data from the database.
+ */
+ private abstract class LoadingAsyncTask extends AsyncTask<Void, Void, Void> {
+ protected Uri mUri;
+ protected String mContentType;
+ protected String mDisplayName;
+ protected String mLookupKey;
+ protected byte[] mBitmapData;
+ protected long mPhotoId;
+
+ public LoadingAsyncTask(Uri uri) {
+ mUri = uri;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ mContentType = mContext.getContentResolver().getType(mUri);
+ loadData();
+ loadPhoto();
+ return null;
+ }
+
+ protected abstract void loadData();
+
+ private void loadPhoto() {
+ if (mPhotoId == 0) {
+ return;
+ }
+
+ ContentResolver resolver = mContext.getContentResolver();
+ Cursor cursor = resolver.query(Data.CONTENT_URI, PHOTO_COLUMNS, PHOTO_SELECTION,
+ new String[] { String.valueOf(mPhotoId) }, null);
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ mBitmapData = cursor.getBlob(PHOTO_PHOTO_COLUMN_INDEX);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ }
+ }
+
+ private final class ContactLoadingAsyncTask extends LoadingAsyncTask {
+ public ContactLoadingAsyncTask(Uri uri) {
+ super(uri);
+ }
+
+ @Override
+ protected void loadData() {
+ ContentResolver resolver = mContext.getContentResolver();
+ Cursor cursor = resolver.query(mUri, CONTACT_COLUMNS, null, null, null);
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ mDisplayName = cursor.getString(CONTACT_DISPLAY_NAME_COLUMN_INDEX);
+ mPhotoId = cursor.getLong(CONTACT_PHOTO_ID_COLUMN_INDEX);
+ mLookupKey = cursor.getString(CONTACT_LOOKUP_KEY_COLUMN_INDEX);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ }
+ @Override
+ protected void onPostExecute(Void result) {
+ createContactShortcutIntent(mUri, mContentType, mDisplayName, mLookupKey, mBitmapData);
+ }
+ }
+
+ private final class PhoneNumberLoadingAsyncTask extends LoadingAsyncTask {
+ private final String mShortcutAction;
+ private String mPhoneNumber;
+ private int mPhoneType;
+ private String mPhoneLabel;
+
+ public PhoneNumberLoadingAsyncTask(Uri uri, String shortcutAction) {
+ super(uri);
+ mShortcutAction = shortcutAction;
+ }
+
+ @Override
+ protected void loadData() {
+ ContentResolver resolver = mContext.getContentResolver();
+ Cursor cursor = resolver.query(mUri, PHONE_COLUMNS, null, null, null);
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ mDisplayName = cursor.getString(PHONE_DISPLAY_NAME_COLUMN_INDEX);
+ mPhotoId = cursor.getLong(PHONE_PHOTO_ID_COLUMN_INDEX);
+ mPhoneNumber = cursor.getString(PHONE_NUMBER_COLUMN_INDEX);
+ mPhoneType = cursor.getInt(PHONE_TYPE_COLUMN_INDEX);
+ mPhoneLabel = cursor.getString(PHONE_LABEL_COLUMN_INDEX);
+ mLookupKey = cursor.getString(PHONE_LOOKUP_KEY_COLUMN_INDEX);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ createPhoneNumberShortcutIntent(mUri, mDisplayName, mLookupKey, mBitmapData,
+ mPhoneNumber, mPhoneType, mPhoneLabel, mShortcutAction);
+ }
+ }
+
+ private Drawable getPhotoDrawable(byte[] bitmapData, String displayName, String lookupKey) {
+ if (bitmapData != null) {
+ Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length, null);
+ return new BitmapDrawable(mContext.getResources(), bitmap);
+ } else {
+ return ContactPhotoManager.getDefaultAvatarDrawableForContact(mContext.getResources(),
+ false, new DefaultImageRequest(displayName, lookupKey, false));
+ }
+ }
+
+ private void createContactShortcutIntent(Uri contactUri, String contentType, String displayName,
+ String lookupKey, byte[] bitmapData) {
+ Drawable drawable = getPhotoDrawable(bitmapData, displayName, lookupKey);
+
+ // Use an implicit intent without a package name set. It is reasonable for a disambiguation
+ // dialog to appear when opening QuickContacts from the launcher. Plus, this will be more
+ // resistant to future package name changes done to Contacts.
+ Intent shortcutIntent = new Intent(ContactsContract.QuickContact.ACTION_QUICK_CONTACT);
+
+ // When starting from the launcher, start in a new, cleared task.
+ // CLEAR_WHEN_TASK_RESET cannot reset the root of a task, so we
+ // clear the whole thing preemptively here since QuickContactActivity will
+ // finish itself when launching other detail activities. We need to use
+ // Intent.FLAG_ACTIVITY_NO_ANIMATION since not all versions of launcher will respect
+ // the INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION intent extra.
+ shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
+ | Intent.FLAG_ACTIVITY_NO_ANIMATION);
+
+ // Tell the launcher to not do its animation, because we are doing our own
+ shortcutIntent.putExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true);
+
+ shortcutIntent.setDataAndType(contactUri, contentType);
+ shortcutIntent.putExtra(ContactsContract.QuickContact.EXTRA_EXCLUDE_MIMES,
+ (String[]) null);
+
+ final Bitmap icon = generateQuickContactIcon(drawable);
+
+ Intent intent = new Intent();
+ intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);
+ intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
+ if (TextUtils.isEmpty(displayName)) {
+ intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, mContext.getResources().getString(
+ R.string.missing_name));
+ } else {
+ intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, displayName);
+ }
+
+ mListener.onShortcutIntentCreated(contactUri, intent);
+ }
+
+ private void createPhoneNumberShortcutIntent(Uri uri, String displayName, String lookupKey,
+ byte[] bitmapData, String phoneNumber, int phoneType, String phoneLabel,
+ String shortcutAction) {
+ Drawable drawable = getPhotoDrawable(bitmapData, displayName, lookupKey);
+
+ Bitmap bitmap;
+ Uri phoneUri;
+ if (Intent.ACTION_CALL.equals(shortcutAction)) {
+ // Make the URI a direct tel: URI so that it will always continue to work
+ phoneUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null);
+ bitmap = generatePhoneNumberIcon(drawable, phoneType, phoneLabel,
+ R.drawable.ic_call);
+ } else {
+ phoneUri = Uri.fromParts(ContactsUtils.SCHEME_SMSTO, phoneNumber, null);
+ bitmap = generatePhoneNumberIcon(drawable, phoneType, phoneLabel,
+ R.drawable.ic_message_24dp_mirrored);
+ }
+
+ Intent shortcutIntent = new Intent(shortcutAction, phoneUri);
+ shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+
+ Intent intent = new Intent();
+ intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
+ intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
+
+ if (TextUtils.isEmpty(displayName)) {
+ displayName = mContext.getResources().getString(R.string.missing_name);
+ }
+ if (TextUtils.equals(shortcutAction, Intent.ACTION_CALL)) {
+ intent.putExtra(Intent.EXTRA_SHORTCUT_NAME,
+ mContext.getResources().getString(R.string.call_by_shortcut, displayName));
+ } else if (TextUtils.equals(shortcutAction, Intent.ACTION_SENDTO)) {
+ intent.putExtra(Intent.EXTRA_SHORTCUT_NAME,
+ mContext.getResources().getString(R.string.sms_by_shortcut, displayName));
+ }
+
+ mListener.onShortcutIntentCreated(uri, intent);
+ }
+
+ private Bitmap generateQuickContactIcon(Drawable photo) {
+
+ // Setup the drawing classes
+ Bitmap bitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+
+ // Copy in the photo
+ Rect dst = new Rect(0,0, mIconSize, mIconSize);
+ photo.setBounds(dst);
+ photo.draw(canvas);
+
+ // Draw the icon with a rounded border
+ RoundedBitmapDrawable roundedDrawable =
+ RoundedBitmapDrawableFactory.create(mResources, bitmap);
+ roundedDrawable.setAntiAlias(true);
+ roundedDrawable.setCornerRadius(mIconSize / 2);
+ Bitmap roundedBitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888);
+ canvas.setBitmap(roundedBitmap);
+ roundedDrawable.setBounds(dst);
+ roundedDrawable.draw(canvas);
+ canvas.setBitmap(null);
+
+ return roundedBitmap;
+ }
+
+ /**
+ * 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.
+ */
+ private Bitmap generatePhoneNumberIcon(Drawable photo, int phoneType, String phoneLabel,
+ int actionResId) {
+ final Resources r = mContext.getResources();
+ final float density = r.getDisplayMetrics().density;
+
+ Bitmap phoneIcon = ((BitmapDrawable) r.getDrawableForDensity(actionResId, mIconDensity))
+ .getBitmap();
+
+ Bitmap icon = generateQuickContactIcon(photo);
+ Canvas canvas = new Canvas(icon);
+
+ // Copy in the photo
+ Paint photoPaint = new Paint();
+ photoPaint.setDither(true);
+ photoPaint.setFilterBitmap(true);
+ Rect dst = new Rect(0, 0, mIconSize, mIconSize);
+
+ // Create an overlay for the phone number type
+ CharSequence overlay = Phone.getTypeLabel(r, phoneType, phoneLabel);
+
+ if (overlay != null) {
+ TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
+ textPaint.setTextSize(r.getDimension(R.dimen.shortcut_overlay_text_size));
+ textPaint.setColor(r.getColor(R.color.textColorIconOverlay));
+ textPaint.setShadowLayer(4f, 0, 2f, r.getColor(R.color.textColorIconOverlayShadow));
+
+ final FontMetricsInt fmi = textPaint.getFontMetricsInt();
+
+ // First fill in a darker background around the text to be drawn
+ final Paint workPaint = new Paint();
+ workPaint.setColor(mOverlayTextBackgroundColor);
+ workPaint.setStyle(Paint.Style.FILL);
+ final int textPadding = r
+ .getDimensionPixelOffset(R.dimen.shortcut_overlay_text_background_padding);
+ final int textBandHeight = (fmi.descent - fmi.ascent) + textPadding * 2;
+ dst.set(0, mIconSize - textBandHeight, mIconSize, mIconSize);
+ canvas.drawRect(dst, workPaint);
+
+ overlay = TextUtils.ellipsize(overlay, textPaint, mIconSize, TruncateAt.END);
+ final float textWidth = textPaint.measureText(overlay, 0, overlay.length());
+ canvas.drawText(overlay, 0, overlay.length(), (mIconSize - textWidth) / 2, mIconSize
+ - fmi.descent - textPadding, textPaint);
+ }
+
+ // Draw the phone action icon as an overlay
+ Rect src = new Rect(0, 0, phoneIcon.getWidth(), phoneIcon.getHeight());
+ int iconWidth = icon.getWidth();
+ dst.set(iconWidth - ((int) (20 * density)), -1,
+ iconWidth, ((int) (19 * density)));
+ canvas.drawBitmap(phoneIcon, src, dst, photoPaint);
+
+ canvas.setBitmap(null);
+
+ return icon;
+ }
+}
diff --git a/src/com/android/contacts/common/list/ViewPagerTabStrip.java b/src/com/android/contacts/common/list/ViewPagerTabStrip.java
new file mode 100644
index 0000000..c8ae21a
--- /dev/null
+++ b/src/com/android/contacts/common/list/ViewPagerTabStrip.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 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.common.list;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.contacts.common.R;
+
+public class ViewPagerTabStrip extends LinearLayout {
+ private int mSelectedUnderlineThickness;
+ private final Paint mSelectedUnderlinePaint;
+
+ private int mIndexForSelection;
+ private float mSelectionOffset;
+
+ public ViewPagerTabStrip(Context context) {
+ this(context, null);
+ }
+
+ public ViewPagerTabStrip(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ final Resources res = context.getResources();
+
+ mSelectedUnderlineThickness =
+ res.getDimensionPixelSize(R.dimen.tab_selected_underline_height);
+ int underlineColor = res.getColor(R.color.tab_selected_underline_color);
+ int backgroundColor = res.getColor(R.color.actionbar_background_color);
+
+ mSelectedUnderlinePaint = new Paint();
+ mSelectedUnderlinePaint.setColor(underlineColor);
+
+ setBackgroundColor(backgroundColor);
+ setWillNotDraw(false);
+ }
+
+ /**
+ * Notifies this view that view pager has been scrolled. We save the tab index
+ * and selection offset for interpolating the position and width of selection
+ * underline.
+ */
+ void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ mIndexForSelection = position;
+ mSelectionOffset = positionOffset;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int childCount = getChildCount();
+
+ // Thick colored underline below the current selection
+ if (childCount > 0) {
+ View selectedTitle = getChildAt(mIndexForSelection);
+
+ if (selectedTitle == null) {
+ // The view pager's tab count changed but we weren't notified yet. Ignore this draw
+ // pass, when we get a new selection we will update and draw the selection strip in
+ // the correct place.
+ return;
+ }
+ int selectedLeft = selectedTitle.getLeft();
+ int selectedRight = selectedTitle.getRight();
+ final boolean isRtl = isRtl();
+ final boolean hasNextTab = isRtl ? mIndexForSelection > 0
+ : (mIndexForSelection < (getChildCount() - 1));
+ if ((mSelectionOffset > 0.0f) && hasNextTab) {
+ // Draw the selection partway between the tabs
+ View nextTitle = getChildAt(mIndexForSelection + (isRtl ? -1 : 1));
+ int nextLeft = nextTitle.getLeft();
+ int nextRight = nextTitle.getRight();
+
+ selectedLeft = (int) (mSelectionOffset * nextLeft +
+ (1.0f - mSelectionOffset) * selectedLeft);
+ selectedRight = (int) (mSelectionOffset * nextRight +
+ (1.0f - mSelectionOffset) * selectedRight);
+ }
+
+ int height = getHeight();
+ canvas.drawRect(selectedLeft, height - mSelectedUnderlineThickness,
+ selectedRight, height, mSelectedUnderlinePaint);
+ }
+ }
+
+ private boolean isRtl() {
+ return getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/common/list/ViewPagerTabs.java b/src/com/android/contacts/common/list/ViewPagerTabs.java
new file mode 100644
index 0000000..48de6af
--- /dev/null
+++ b/src/com/android/contacts/common/list/ViewPagerTabs.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2014 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.common.list;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Outline;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.widget.FrameLayout;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.CompatUtils;
+
+/**
+ * Lightweight implementation of ViewPager tabs. This looks similar to traditional actionBar tabs,
+ * but allows for the view containing the tabs to be placed anywhere on screen. Text-related
+ * attributes can also be assigned in XML - these will get propogated to the child TextViews
+ * automatically.
+ */
+public class ViewPagerTabs extends HorizontalScrollView implements ViewPager.OnPageChangeListener {
+
+ ViewPager mPager;
+ private ViewPagerTabStrip mTabStrip;
+
+ /**
+ * Linearlayout that will contain the TextViews serving as tabs. This is the only child
+ * of the parent HorizontalScrollView.
+ */
+ final int mTextStyle;
+ final ColorStateList mTextColor;
+ final int mTextSize;
+ final boolean mTextAllCaps;
+ int mPrevSelected = -1;
+ int mSidePadding;
+
+ private int[] mTabIcons;
+ // For displaying the unread count next to the tab icon.
+ private int[] mUnreadCounts;
+
+ private static final ViewOutlineProvider VIEW_BOUNDS_OUTLINE_PROVIDER;
+ static {
+ if (CompatUtils.isLollipopCompatible()) {
+ VIEW_BOUNDS_OUTLINE_PROVIDER = new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRect(0, 0, view.getWidth(), view.getHeight());
+ }
+ };
+ } else {
+ VIEW_BOUNDS_OUTLINE_PROVIDER = null;
+ }
+ }
+
+ private static final int TAB_SIDE_PADDING_IN_DPS = 10;
+
+ // TODO: This should use <declare-styleable> in the future
+ private static final int[] ATTRS = new int[] {
+ android.R.attr.textSize,
+ android.R.attr.textStyle,
+ android.R.attr.textColor,
+ android.R.attr.textAllCaps
+ };
+
+ /**
+ * Simulates actionbar tab behavior by showing a toast with the tab title when long clicked.
+ */
+ private class OnTabLongClickListener implements OnLongClickListener {
+ final int mPosition;
+
+ public OnTabLongClickListener(int position) {
+ mPosition = position;
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ final int[] screenPos = new int[2];
+ getLocationOnScreen(screenPos);
+
+ final Context context = getContext();
+ final int width = getWidth();
+ final int height = getHeight();
+ final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
+
+ Toast toast = Toast.makeText(context, mPager.getAdapter().getPageTitle(mPosition),
+ Toast.LENGTH_SHORT);
+
+ // Show the toast under the tab
+ toast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
+ (screenPos[0] + width / 2) - screenWidth / 2, screenPos[1] + height);
+
+ toast.show();
+ return true;
+ }
+ }
+
+ public ViewPagerTabs(Context context) {
+ this(context, null);
+ }
+
+ public ViewPagerTabs(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ViewPagerTabs(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setFillViewport(true);
+
+ mSidePadding = (int) (getResources().getDisplayMetrics().density * TAB_SIDE_PADDING_IN_DPS);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
+ mTextSize = a.getDimensionPixelSize(0, 0);
+ mTextStyle = a.getInt(1, 0);
+ mTextColor = a.getColorStateList(2);
+ mTextAllCaps = a.getBoolean(3, false);
+
+ mTabStrip = new ViewPagerTabStrip(context);
+ addView(mTabStrip,
+ new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
+ a.recycle();
+
+ if (CompatUtils.isLollipopCompatible()) {
+ // enable shadow casting from view bounds
+ setOutlineProvider(VIEW_BOUNDS_OUTLINE_PROVIDER);
+ }
+ }
+
+ public void setViewPager(ViewPager viewPager) {
+ mPager = viewPager;
+ addTabs(mPager.getAdapter());
+ }
+
+ /**
+ * Set the tab icons and initialize an array for unread counts the same length as the icon
+ * array.
+ *
+ * @param tabIcons An array representing the tab icons in order.
+ */
+ public void configureTabIcons(int[] tabIcons) {
+ mTabIcons = tabIcons;
+ mUnreadCounts = new int[tabIcons.length];
+ }
+
+ public void setUnreadCount(int count, int position) {
+ if (mUnreadCounts == null || position >= mUnreadCounts.length) {
+ return;
+ }
+ mUnreadCounts[position] = count;
+ }
+
+ private void addTabs(PagerAdapter adapter) {
+ mTabStrip.removeAllViews();
+
+ final int count = adapter.getCount();
+ for (int i = 0; i < count; i++) {
+ addTab(adapter.getPageTitle(i), i);
+ }
+ }
+
+ private void addTab(CharSequence tabTitle, final int position) {
+ View tabView;
+ if (mTabIcons != null && position < mTabIcons.length) {
+ View layout = LayoutInflater.from(getContext()).inflate(
+ R.layout.unread_count_tab, null);
+ View iconView = layout.findViewById(R.id.icon);
+ iconView.setBackgroundResource(mTabIcons[position]);
+ iconView.setContentDescription(tabTitle);
+ TextView textView = (TextView) layout.findViewById(R.id.count);
+ if (mUnreadCounts != null && mUnreadCounts[position] > 0) {
+ textView.setText(Integer.toString(mUnreadCounts[position]));
+ textView.setVisibility(View.VISIBLE);
+ iconView.setContentDescription(getResources().getQuantityString(
+ R.plurals.tab_title_with_unread_items,
+ mUnreadCounts[position],
+ tabTitle.toString(),
+ mUnreadCounts[position]));
+ } else {
+ textView.setVisibility(View.INVISIBLE);
+ iconView.setContentDescription(tabTitle);
+ }
+ tabView = layout;
+ } else {
+ final TextView textView = new TextView(getContext());
+ textView.setText(tabTitle);
+ textView.setBackgroundResource(R.drawable.view_pager_tab_background);
+
+ // Assign various text appearance related attributes to child views.
+ if (mTextStyle > 0) {
+ textView.setTypeface(textView.getTypeface(), mTextStyle);
+ }
+ if (mTextSize > 0) {
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
+ }
+ if (mTextColor != null) {
+ textView.setTextColor(mTextColor);
+ }
+ textView.setAllCaps(mTextAllCaps);
+ textView.setGravity(Gravity.CENTER);
+
+ tabView = textView;
+ }
+
+ tabView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mPager.setCurrentItem(getRtlPosition(position));
+ }
+ });
+
+ tabView.setOnLongClickListener(new OnTabLongClickListener(position));
+
+ tabView.setPadding(mSidePadding, 0, mSidePadding, 0);
+
+ mTabStrip.addView(tabView, position, new LinearLayout.LayoutParams(
+ LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT, 1));
+
+ // Default to the first child being selected
+ if (position == 0) {
+ mPrevSelected = 0;
+ tabView.setSelected(true);
+ }
+ }
+
+ /**
+ * Remove a tab at a certain index.
+ *
+ * @param index The index of the tab view we wish to remove.
+ */
+ public void removeTab(int index) {
+ View view = mTabStrip.getChildAt(index);
+ if (view != null) {
+ mTabStrip.removeView(view);
+ }
+ }
+
+ /**
+ * Refresh a tab at a certain index by removing it and reconstructing it.
+ *
+ * @param index The index of the tab view we wish to update.
+ */
+ public void updateTab(int index) {
+ removeTab(index);
+
+ if (index < mPager.getAdapter().getCount()) {
+ addTab(mPager.getAdapter().getPageTitle(index), index);
+ }
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ position = getRtlPosition(position);
+ int tabStripChildCount = mTabStrip.getChildCount();
+ if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+ return;
+ }
+
+ mTabStrip.onPageScrolled(position, positionOffset, positionOffsetPixels);
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ position = getRtlPosition(position);
+ int tabStripChildCount = mTabStrip.getChildCount();
+ if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+ return;
+ }
+
+ if (mPrevSelected >= 0 && mPrevSelected < tabStripChildCount) {
+ mTabStrip.getChildAt(mPrevSelected).setSelected(false);
+ }
+ final View selectedChild = mTabStrip.getChildAt(position);
+ selectedChild.setSelected(true);
+
+ // Update scroll position
+ final int scrollPos = selectedChild.getLeft() - (getWidth() - selectedChild.getWidth()) / 2;
+ smoothScrollTo(scrollPos, 0);
+ mPrevSelected = position;
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ }
+
+ private int getRtlPosition(int position) {
+ if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ return mTabStrip.getChildCount() - 1 - position;
+ }
+ return position;
+ }
+}
+
diff --git a/src/com/android/contacts/common/location/CountryDetector.java b/src/com/android/contacts/common/location/CountryDetector.java
new file mode 100644
index 0000000..2d29a69
--- /dev/null
+++ b/src/com/android/contacts/common/location/CountryDetector.java
@@ -0,0 +1,130 @@
+package com.android.contacts.common.location;
+
+import android.content.Context;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.contacts.common.testing.NeededForTesting;
+
+import java.util.Locale;
+
+/**
+ * This class is used to detect the country where the user is. It is a simplified version of the
+ * country detector service in the framework. The sources of country location are queried in the
+ * following order of reliability:
+ * <ul>
+ * <li>Mobile network</li>
+ * <li>SIM's country</li>
+ * <li>User's default locale</li>
+ * </ul>
+ *
+ * As far as possible this class tries to replicate the behavior of the system's country detector
+ * service:
+ * 1) Order in priority of sources of country location
+ * 2) Mobile network information provided by CDMA phones is ignored
+ */
+public class CountryDetector {
+ private static final String TAG = "CountryDetector";
+
+ private static CountryDetector sInstance;
+
+ private final Context mContext;
+ private final LocaleProvider mLocaleProvider;
+ private final TelephonyManager mTelephonyManager;
+
+ // Used as a default country code when all the sources of country data have failed in the
+ // exceedingly rare event that the device does not have a default locale set for some reason.
+ private final String DEFAULT_COUNTRY_ISO = "US";
+
+ /**
+ * Class that can be used to return the user's default locale. This is in its own class so that
+ * it can be mocked out.
+ */
+ public static class LocaleProvider {
+ public Locale getDefaultLocale() {
+ return Locale.getDefault();
+ }
+ }
+
+ private CountryDetector(Context context) {
+ this (context, (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
+ new LocaleProvider());
+ }
+
+ private CountryDetector(Context context, TelephonyManager telephonyManager,
+ LocaleProvider localeProvider) {
+ mTelephonyManager = telephonyManager;
+ mLocaleProvider = localeProvider;
+ mContext = context;
+ }
+
+ /**
+ * Factory method for {@link CountryDetector} that allows the caller to provide mock objects.
+ */
+ @NeededForTesting
+ public CountryDetector getInstanceForTest(Context context, TelephonyManager telephonyManager,
+ LocaleProvider localeProvider) {
+ return new CountryDetector(context, telephonyManager, localeProvider);
+ }
+
+ /**
+ * Returns the instance of the country detector. {@link #initialize(Context)} must have been
+ * called previously.
+ *
+ * @return the initialized country detector.
+ */
+ public synchronized static CountryDetector getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new CountryDetector(context.getApplicationContext());
+ }
+ return sInstance;
+ }
+
+ public String getCurrentCountryIso() {
+ String result = null;
+ if (isNetworkCountryCodeAvailable()) {
+ result = getNetworkBasedCountryIso();
+ }
+ if (TextUtils.isEmpty(result)) {
+ result = getSimBasedCountryIso();
+ }
+ if (TextUtils.isEmpty(result)) {
+ result = getLocaleBasedCountryIso();
+ }
+ if (TextUtils.isEmpty(result)) {
+ result = DEFAULT_COUNTRY_ISO;
+ }
+ return result.toUpperCase(Locale.US);
+ }
+
+ /**
+ * @return the country code of the current telephony network the user is connected to.
+ */
+ private String getNetworkBasedCountryIso() {
+ return mTelephonyManager.getNetworkCountryIso();
+ }
+
+ /**
+ * @return the country code of the SIM card currently inserted in the device.
+ */
+ private String getSimBasedCountryIso() {
+ return mTelephonyManager.getSimCountryIso();
+ }
+
+ /**
+ * @return the country code of the user's currently selected locale.
+ */
+ private String getLocaleBasedCountryIso() {
+ Locale defaultLocale = mLocaleProvider.getDefaultLocale();
+ if (defaultLocale != null) {
+ return defaultLocale.getCountry();
+ }
+ return null;
+ }
+
+ private boolean isNetworkCountryCodeAvailable() {
+ // On CDMA TelephonyManager.getNetworkCountryIso() just returns the SIM's country code.
+ return mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM;
+ }
+}
diff --git a/src/com/android/contacts/common/logging/ListEvent.java b/src/com/android/contacts/common/logging/ListEvent.java
new file mode 100644
index 0000000..7d019dd
--- /dev/null
+++ b/src/com/android/contacts/common/logging/ListEvent.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 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.common.logging;
+
+import com.google.common.base.Objects;
+
+/**
+ * Describes how user view and use a list
+ */
+public final class ListEvent {
+
+ /** The type of action taken by the user. **/
+ public int actionType;
+
+ /** The type of list the user is viewing. **/
+ public int listType;
+
+ /** The number of contacts in the list. **/
+ public int count;
+
+ /** The index of contact clicked by user. **/
+ public int clickedIndex = -1;
+
+ /** The number of contact selected when user takes an action (link, delete, share, etc). **/
+ public int numSelected;
+
+ // Should match ContactsExtension.ListEvent.ActionType values in
+ // http://cs/google3/logs/proto/wireless/android/contacts/contacts_extensions.proto
+ public static final class ActionType {
+ public static final int UNKNOWN = 0;
+ public static final int LOAD = 1;
+ public static final int CLICK = 2;
+ public static final int SELECT = 3;
+ public static final int SHARE = 4;
+ public static final int DELETE = 5;
+ public static final int LINK = 6;
+ public static final int REMOVE_LABEL = 7;
+
+ private ActionType() {
+ }
+ }
+
+ // Should match ContactsExtension.ListEvent.ListType values in
+ // http://cs/google3/logs/proto/wireless/android/contacts/contacts_extensions.proto
+ public static final class ListType {
+ public static final int UNKNOWN_LIST = 0;
+ public static final int ALL_CONTACTS = 1;
+ public static final int ACCOUNT = 2;
+ public static final int GROUP = 3;
+ public static final int SEARCH_RESULT = 4;
+ public static final int DEVICE = 5;
+ public static final int CUSTOM = 6;
+ public static final int STARRED = 7;
+ public static final int PHONE_NUMBERS = 8;
+ public static final int SINGLE_CONTACT = 9;
+ public static final int PICK_CONTACT = 10;
+ public static final int PICK_CONTACT_FOR_SHORTCUT = 11;
+ public static final int PICK_PHONE = 12;
+ public static final int PICK_EMAIL = 13;
+ public static final int PICK_POSTAL = 14;
+ public static final int PICK_JOIN = 15;
+ public static final int PICK_GROUP_MEMBERS = 16;
+
+ private ListType() {
+ }
+ }
+
+ public ListEvent() {
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("actionType", actionType)
+ .add("listType", listType)
+ .add("count", count)
+ .add("clickedIndex", clickedIndex)
+ .add("numSelected", numSelected)
+ .toString();
+ }
+}
diff --git a/src/com/android/contacts/common/logging/Logger.java b/src/com/android/contacts/common/logging/Logger.java
new file mode 100644
index 0000000..c0fbd9a
--- /dev/null
+++ b/src/com/android/contacts/common/logging/Logger.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 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.common.logging;
+
+import android.app.Activity;
+
+import com.android.contacts.common.logging.ScreenEvent.ScreenType;
+import com.android.contactsbind.ObjectFactory;
+
+/**
+ * Logs analytics events.
+ */
+public abstract class Logger {
+ public static final String TAG = "Logger";
+
+ private static Logger getInstance() {
+ return ObjectFactory.getLogger();
+ }
+
+ /**
+ * Logs an event indicating that a screen was displayed.
+ *
+ * @param screenType integer identifier of the displayed screen
+ * @param activity Parent activity of the displayed screen.
+ */
+ public static void logScreenView(Activity activity, int screenType) {
+ logScreenView(activity, screenType, ScreenType.UNKNOWN);
+ }
+
+ /**
+ * @param previousScreenType integer identifier of the displayed screen the user came from.
+ */
+ public static void logScreenView(Activity activity, int screenType, int previousScreenType) {
+ final Logger logger = getInstance();
+ if (logger != null) {
+ logger.logScreenViewImpl(screenType, previousScreenType);
+ }
+ }
+
+ /**
+ * Logs the results of a user search for a particular contact.
+ */
+ public static void logSearchEvent(SearchState searchState) {
+ final Logger logger = getInstance();
+ if (logger != null) {
+ logger.logSearchEventImpl(searchState);
+ }
+ }
+
+ /**
+ * Logs how users view and use a contacts list. See {@link ListEvent} for definition of
+ * parameters.
+ */
+ public static void logListEvent(int actionType, int listType, int count, int clickedIndex,
+ int numSelected) {
+ final ListEvent event = new ListEvent();
+ event.actionType = actionType;
+ event.listType = listType;
+ event.count = count;
+ event.clickedIndex = clickedIndex;
+ event.numSelected = numSelected;
+
+ final Logger logger = getInstance();
+ if (logger != null) {
+ logger.logListEventImpl(event);
+ }
+ }
+
+ public abstract void logScreenViewImpl(int screenType, int previousScreenType);
+ public abstract void logSearchEventImpl(SearchState searchState);
+ public abstract void logListEventImpl(ListEvent event);
+}
diff --git a/src/com/android/contacts/common/logging/ScreenEvent.java b/src/com/android/contacts/common/logging/ScreenEvent.java
new file mode 100644
index 0000000..6af020b
--- /dev/null
+++ b/src/com/android/contacts/common/logging/ScreenEvent.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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.common.logging;
+
+/**
+ * Stores constants identifying individual screens/dialogs/fragments in the application, and also
+ * provides a mapping of integer id -> screen name mappings for analytics purposes.
+ */
+public class ScreenEvent {
+
+ // Should match ContactsExtension.ScreenEvent.ScreenType values in
+ // http://cs/google3/logs/proto/wireless/android/contacts/contacts_extensions.proto
+ public static class ScreenType {
+ public static final int UNKNOWN = 0;
+ public static final int SEARCH = 1;
+ public static final int SEARCH_EXIT = 2;
+ public static final int FAVORITES = 3;
+ public static final int ALL_CONTACTS = 4;
+ public static final int QUICK_CONTACT = 5;
+ public static final int EDITOR = 6;
+ public static final int LIST_ACCOUNT = 7;
+ public static final int LIST_GROUP = 8;
+ public static final int ME_CONTACT = 9;
+ }
+}
diff --git a/src/com/android/contacts/common/logging/SearchState.java b/src/com/android/contacts/common/logging/SearchState.java
new file mode 100644
index 0000000..f4719e4
--- /dev/null
+++ b/src/com/android/contacts/common/logging/SearchState.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 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.common.logging;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.google.common.base.Objects;
+
+/**
+ * Describes the results of a user search for a particular contact.
+ */
+public final class SearchState implements Parcelable {
+
+ /** The length of the query string input by the user. */
+ public int queryLength;
+
+ /** The number of partitions (groups of results) presented to the user. */
+ public int numPartitions;
+
+ /** The total number of results (across all partitions) presented to the user. */
+ public int numResults;
+
+ /** The number of results presented to the user in the partition that was selected. */
+ public int numResultsInSelectedPartition = -1;
+
+ /** The zero-based index of the partition in which the clicked query result resides. */
+ public int selectedPartition = -1;
+
+ /** The index of the clicked query result within its partition. */
+ public int selectedIndexInPartition = -1;
+
+ /**
+ * The zero-based index of the clicked query result among all results displayed to the user
+ * (across partitions).
+ */
+ public int selectedIndex = -1;
+
+ public static final Creator<SearchState> CREATOR = new Creator<SearchState>() {
+ @Override
+ public SearchState createFromParcel(Parcel in) {
+ return new SearchState(in);
+ }
+
+ @Override
+ public SearchState[] newArray(int size) {
+ return new SearchState[size];
+ }
+ };
+
+ public SearchState() {
+ }
+
+ protected SearchState(Parcel source) {
+ readFromParcel(source);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("queryLength", queryLength)
+ .add("numPartitions", numPartitions)
+ .add("numResults", numResults)
+ .add("numResultsInSelectedPartition", numResultsInSelectedPartition)
+ .add("selectedPartition", selectedPartition)
+ .add("selectedIndexInPartition", selectedIndexInPartition)
+ .add("selectedIndex", selectedIndex)
+ .toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(queryLength);
+ dest.writeInt(numPartitions);
+ dest.writeInt(numResults);
+ dest.writeInt(numResultsInSelectedPartition);
+ dest.writeInt(selectedPartition);
+ dest.writeInt(selectedIndexInPartition);
+ dest.writeInt(selectedIndex);
+ }
+
+ private void readFromParcel(Parcel source) {
+ queryLength = source.readInt();
+ numPartitions = source.readInt();
+ numResults = source.readInt();
+ numResultsInSelectedPartition = source.readInt();
+ selectedPartition = source.readInt();
+ selectedIndexInPartition = source.readInt();
+ selectedIndex = source.readInt();
+ }
+}
diff --git a/src/com/android/contacts/common/model/AccountTypeManager.java b/src/com/android/contacts/common/model/AccountTypeManager.java
new file mode 100644
index 0000000..3ef3502
--- /dev/null
+++ b/src/com/android/contacts/common/model/AccountTypeManager.java
@@ -0,0 +1,846 @@
+/*
+ * 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.common.model;
+
+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.Intent;
+import android.content.IntentFilter;
+import android.content.SyncAdapterType;
+import android.content.SyncStatusObserver;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.provider.ContactsContract;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.TimingLogger;
+
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.list.ContactListFilterController;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountTypeWithDataSet;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.ExchangeAccountType;
+import com.android.contacts.common.model.account.ExternalAccountType;
+import com.android.contacts.common.model.account.FallbackAccountType;
+import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.model.account.SamsungAccountType;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.testing.NeededForTesting;
+import com.android.contacts.common.util.Constants;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Singleton holder for all parsed {@link AccountType} available on the
+ * system, typically filled through {@link PackageManager} queries.
+ */
+public abstract class AccountTypeManager {
+ static final String TAG = "AccountTypeManager";
+
+ private static final Object mInitializationLock = new Object();
+ private static AccountTypeManager mAccountTypeManager;
+
+ /**
+ * Requests the singleton instance of {@link AccountTypeManager} with data bound from
+ * the available authenticators. This method can safely be called from the UI thread.
+ */
+ public static AccountTypeManager getInstance(Context context) {
+ synchronized (mInitializationLock) {
+ if (mAccountTypeManager == null) {
+ context = context.getApplicationContext();
+ mAccountTypeManager = new AccountTypeManagerImpl(context);
+ }
+ }
+ return mAccountTypeManager;
+ }
+
+ /**
+ * Set the instance of account type manager. This is only for and should only be used by unit
+ * tests. While having this method is not ideal, it's simpler than the alternative of
+ * holding this as a service in the ContactsApplication context class.
+ *
+ * @param mockManager The mock AccountTypeManager.
+ */
+ @NeededForTesting
+ public static void setInstanceForTest(AccountTypeManager mockManager) {
+ synchronized (mInitializationLock) {
+ mAccountTypeManager = mockManager;
+ }
+ }
+
+ /**
+ * Returns the list of all accounts (if contactWritableOnly is false) or just the list of
+ * contact writable accounts (if contactWritableOnly is true).
+ */
+ // TODO: Consider splitting this into getContactWritableAccounts() and getAllAccounts()
+ public abstract List<AccountWithDataSet> getAccounts(boolean contactWritableOnly);
+
+ /**
+ * Sort accounts based on default account.
+ */
+ public abstract void sortAccounts(AccountWithDataSet defaultAccount);
+
+ /**
+ * Returns the list of accounts that are group writable.
+ */
+ public abstract List<AccountWithDataSet> getGroupWritableAccounts();
+
+ public abstract AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet);
+
+ public final AccountType getAccountType(String accountType, String dataSet) {
+ return getAccountType(AccountTypeWithDataSet.get(accountType, dataSet));
+ }
+
+ public final AccountType getAccountTypeForAccount(AccountWithDataSet account) {
+ if (account != null) {
+ return getAccountType(account.getAccountTypeWithDataSet());
+ }
+ return getAccountType(null, null);
+ }
+
+ /**
+ * @return Unmodifiable map from {@link AccountTypeWithDataSet}s to {@link AccountType}s
+ * which support the "invite" feature and have one or more account.
+ *
+ * This is a filtered down and more "usable" list compared to
+ * {@link #getAllInvitableAccountTypes}, where usable is defined as:
+ * (1) making sure that the app that contributed the account type is not disabled
+ * (in order to avoid presenting the user with an option that does nothing), and
+ * (2) that there is at least one raw contact with that account type in the database
+ * (assuming that the user probably doesn't use that account type).
+ *
+ * Warning: Don't use on the UI thread because this can scan the database.
+ */
+ public abstract Map<AccountTypeWithDataSet, AccountType> getUsableInvitableAccountTypes();
+
+ /**
+ * Find the best {@link DataKind} matching the requested
+ * {@link AccountType#accountType}, {@link AccountType#dataSet}, and {@link DataKind#mimeType}.
+ * If no direct match found, we try searching {@link FallbackAccountType}.
+ */
+ public DataKind getKindOrFallback(AccountType type, String mimeType) {
+ return type == null ? null : type.getKindForMimetype(mimeType);
+ }
+
+ /**
+ * Returns all registered {@link AccountType}s, including extension ones.
+ *
+ * @param contactWritableOnly if true, it only returns ones that support writing contacts.
+ */
+ public abstract List<AccountType> getAccountTypes(boolean contactWritableOnly);
+
+ /**
+ * @param contactWritableOnly if true, it only returns ones that support writing contacts.
+ * @return true when this instance contains the given account.
+ */
+ public boolean contains(AccountWithDataSet account, boolean contactWritableOnly) {
+ for (AccountWithDataSet account_2 : getAccounts(contactWritableOnly)) {
+ if (account.equals(account_2)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+class AccountComparator implements Comparator<AccountWithDataSet> {
+ private AccountWithDataSet mDefaultAccount;
+
+ public AccountComparator(AccountWithDataSet defaultAccount) {
+ mDefaultAccount = defaultAccount;
+ }
+
+ @Override
+ public int compare(AccountWithDataSet a, AccountWithDataSet b) {
+ if (Objects.equal(a.name, b.name) && Objects.equal(a.type, b.type)
+ && Objects.equal(a.dataSet, b.dataSet)) {
+ return 0;
+ } else if (b.name == null || b.type == null) {
+ return -1;
+ } else if (a.name == null || a.type == null) {
+ return 1;
+ } else if (isWritableGoogleAccount(a) && a.equals(mDefaultAccount)) {
+ return -1;
+ } else if (isWritableGoogleAccount(b) && b.equals(mDefaultAccount)) {
+ return 1;
+ } else if (isWritableGoogleAccount(a) && !isWritableGoogleAccount(b)) {
+ return -1;
+ } else if (isWritableGoogleAccount(b) && !isWritableGoogleAccount(a)) {
+ return 1;
+ } else {
+ int diff = a.name.compareToIgnoreCase(b.name);
+ if (diff != 0) {
+ return diff;
+ }
+ diff = a.type.compareToIgnoreCase(b.type);
+ if (diff != 0) {
+ return diff;
+ }
+
+ // Accounts without data sets get sorted before those that have them.
+ if (a.dataSet != null) {
+ return b.dataSet == null ? 1 : a.dataSet.compareToIgnoreCase(b.dataSet);
+ } else {
+ return -1;
+ }
+ }
+ }
+
+ private static boolean isWritableGoogleAccount(AccountWithDataSet account) {
+ return GoogleAccountType.ACCOUNT_TYPE.equals(account.type) && account.dataSet == null;
+ }
+}
+
+class AccountTypeManagerImpl extends AccountTypeManager
+ implements OnAccountsUpdateListener, SyncStatusObserver {
+
+ private static final Map<AccountTypeWithDataSet, AccountType>
+ EMPTY_UNMODIFIABLE_ACCOUNT_TYPE_MAP =
+ Collections.unmodifiableMap(new HashMap<AccountTypeWithDataSet, AccountType>());
+
+ /**
+ * A sample contact URI used to test whether any activities will respond to an
+ * invitable intent with the given URI as the intent data. This doesn't need to be
+ * specific to a real contact because an app that intercepts the intent should probably do so
+ * for all types of contact URIs.
+ */
+ private static final Uri SAMPLE_CONTACT_URI = ContactsContract.Contacts.getLookupUri(
+ 1, "xxx");
+
+ private Context mContext;
+ private AccountManager mAccountManager;
+
+ private AccountType mFallbackAccountType;
+
+ private List<AccountWithDataSet> mAccounts = Lists.newArrayList();
+ private List<AccountWithDataSet> mContactWritableAccounts = Lists.newArrayList();
+ private List<AccountWithDataSet> mGroupWritableAccounts = Lists.newArrayList();
+ private Map<AccountTypeWithDataSet, AccountType> mAccountTypesWithDataSets = Maps.newHashMap();
+ private Map<AccountTypeWithDataSet, AccountType> mInvitableAccountTypes =
+ EMPTY_UNMODIFIABLE_ACCOUNT_TYPE_MAP;
+
+ private final InvitableAccountTypeCache mInvitableAccountTypeCache;
+
+ /**
+ * The boolean value is equal to true if the {@link InvitableAccountTypeCache} has been
+ * initialized. False otherwise.
+ */
+ private final AtomicBoolean mInvitablesCacheIsInitialized = new AtomicBoolean(false);
+
+ /**
+ * The boolean value is equal to true if the {@link FindInvitablesTask} is still executing.
+ * False otherwise.
+ */
+ private final AtomicBoolean mInvitablesTaskIsRunning = new AtomicBoolean(false);
+
+ private static final int MESSAGE_LOAD_DATA = 0;
+ private static final int MESSAGE_PROCESS_BROADCAST_INTENT = 1;
+
+ private HandlerThread mListenerThread;
+ private Handler mListenerHandler;
+
+ private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
+ private final Runnable mCheckFilterValidityRunnable = new Runnable () {
+ @Override
+ public void run() {
+ ContactListFilterController.getInstance(mContext).checkFilterValidity(true);
+ }
+ };
+
+ private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Message msg = mListenerHandler.obtainMessage(MESSAGE_PROCESS_BROADCAST_INTENT, intent);
+ mListenerHandler.sendMessage(msg);
+ }
+
+ };
+
+ /* A latch that ensures that asynchronous initialization completes before data is used */
+ private volatile CountDownLatch mInitializationLatch = new CountDownLatch(1);
+
+ /**
+ * Internal constructor that only performs initial parsing.
+ */
+ public AccountTypeManagerImpl(Context context) {
+ mContext = context;
+ mFallbackAccountType = new FallbackAccountType(context);
+
+ mAccountManager = AccountManager.get(mContext);
+
+ mListenerThread = new HandlerThread("AccountChangeListener");
+ mListenerThread.start();
+ mListenerHandler = new Handler(mListenerThread.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_LOAD_DATA:
+ loadAccountsInBackground();
+ break;
+ case MESSAGE_PROCESS_BROADCAST_INTENT:
+ processBroadcastIntent((Intent) msg.obj);
+ break;
+ }
+ }
+ };
+
+ mInvitableAccountTypeCache = new InvitableAccountTypeCache();
+
+ // Request updates when packages or accounts change
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+ IntentFilter sdFilter = new IntentFilter();
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ mContext.registerReceiver(mBroadcastReceiver, sdFilter);
+
+ // Request updates when locale is changed so that the order of each field will
+ // be able to be changed on the locale change.
+ filter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+
+ mAccountManager.addOnAccountsUpdatedListener(this, mListenerHandler, false);
+
+ ContentResolver.addStatusChangeListener(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, this);
+
+ mListenerHandler.sendEmptyMessage(MESSAGE_LOAD_DATA);
+ }
+
+ @Override
+ public void onStatusChanged(int which) {
+ mListenerHandler.sendEmptyMessage(MESSAGE_LOAD_DATA);
+ }
+
+ public void processBroadcastIntent(Intent intent) {
+ mListenerHandler.sendEmptyMessage(MESSAGE_LOAD_DATA);
+ }
+
+ /* This notification will arrive on the background thread */
+ public void onAccountsUpdated(Account[] accounts) {
+ // Refresh to catch any changed accounts
+ loadAccountsInBackground();
+ }
+
+ /**
+ * Returns instantly if accounts and account types have already been loaded.
+ * Otherwise waits for the background thread to complete the loading.
+ */
+ void ensureAccountsLoaded() {
+ CountDownLatch latch = mInitializationLatch;
+ if (latch == null) {
+ return;
+ }
+ while (true) {
+ try {
+ latch.await();
+ return;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Loads account list and corresponding account types (potentially with data sets). Always
+ * called on a background thread.
+ */
+ protected void loadAccountsInBackground() {
+ if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
+ Log.d(Constants.PERFORMANCE_TAG, "AccountTypeManager.loadAccountsInBackground start");
+ }
+ TimingLogger timings = new TimingLogger(TAG, "loadAccountsInBackground");
+ final long startTime = SystemClock.currentThreadTimeMillis();
+ final long startTimeWall = SystemClock.elapsedRealtime();
+
+ // Account types, keyed off the account type and data set concatenation.
+ final Map<AccountTypeWithDataSet, AccountType> accountTypesByTypeAndDataSet =
+ Maps.newHashMap();
+
+ // The same AccountTypes, but keyed off {@link RawContacts#ACCOUNT_TYPE}. Since there can
+ // be multiple account types (with different data sets) for the same type of account, each
+ // type string may have multiple AccountType entries.
+ final Map<String, List<AccountType>> accountTypesByType = Maps.newHashMap();
+
+ final List<AccountWithDataSet> allAccounts = Lists.newArrayList();
+ final List<AccountWithDataSet> contactWritableAccounts = Lists.newArrayList();
+ final List<AccountWithDataSet> groupWritableAccounts = Lists.newArrayList();
+ final Set<String> extensionPackages = Sets.newHashSet();
+
+ final AccountManager am = mAccountManager;
+
+ final SyncAdapterType[] syncs = ContentResolver.getSyncAdapterTypes();
+ final AuthenticatorDescription[] auths = am.getAuthenticatorTypes();
+
+ // First process sync adapters to find any that provide contact data.
+ 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 type = sync.accountType;
+ final AuthenticatorDescription auth = findAuthenticator(auths, type);
+ if (auth == null) {
+ Log.w(TAG, "No authenticator found for type=" + type + ", ignoring it.");
+ continue;
+ }
+
+ AccountType accountType;
+ if (GoogleAccountType.ACCOUNT_TYPE.equals(type)) {
+ accountType = new GoogleAccountType(mContext, auth.packageName);
+ } else if (ExchangeAccountType.isExchangeType(type)) {
+ accountType = new ExchangeAccountType(mContext, auth.packageName, type);
+ } else if (SamsungAccountType.isSamsungAccountType(mContext, type,
+ auth.packageName)) {
+ accountType = new SamsungAccountType(mContext, auth.packageName, type);
+ } else {
+ Log.d(TAG, "Registering external account type=" + type
+ + ", packageName=" + auth.packageName);
+ accountType = new ExternalAccountType(mContext, auth.packageName, false);
+ }
+ if (!accountType.isInitialized()) {
+ if (accountType.isEmbedded()) {
+ throw new IllegalStateException("Problem initializing embedded type "
+ + accountType.getClass().getCanonicalName());
+ } else {
+ // Skip external account types that couldn't be initialized.
+ continue;
+ }
+ }
+
+ accountType.accountType = auth.type;
+ accountType.titleRes = auth.labelId;
+ accountType.iconRes = auth.iconId;
+
+ addAccountType(accountType, accountTypesByTypeAndDataSet, accountTypesByType);
+
+ // Check to see if the account type knows of any other non-sync-adapter packages
+ // that may provide other data sets of contact data.
+ extensionPackages.addAll(accountType.getExtensionPackageNames());
+ }
+
+ // If any extension packages were specified, process them as well.
+ if (!extensionPackages.isEmpty()) {
+ Log.d(TAG, "Registering " + extensionPackages.size() + " extension packages");
+ for (String extensionPackage : extensionPackages) {
+ ExternalAccountType accountType =
+ new ExternalAccountType(mContext, extensionPackage, true);
+ if (!accountType.isInitialized()) {
+ // Skip external account types that couldn't be initialized.
+ continue;
+ }
+ if (!accountType.hasContactsMetadata()) {
+ Log.w(TAG, "Skipping extension package " + extensionPackage + " because"
+ + " it doesn't have the CONTACTS_STRUCTURE metadata");
+ continue;
+ }
+ if (TextUtils.isEmpty(accountType.accountType)) {
+ Log.w(TAG, "Skipping extension package " + extensionPackage + " because"
+ + " the CONTACTS_STRUCTURE metadata doesn't have the accountType"
+ + " attribute");
+ continue;
+ }
+ Log.d(TAG, "Registering extension package account type="
+ + accountType.accountType + ", dataSet=" + accountType.dataSet
+ + ", packageName=" + extensionPackage);
+
+ addAccountType(accountType, accountTypesByTypeAndDataSet, accountTypesByType);
+ }
+ }
+ timings.addSplit("Loaded account types");
+
+ // Map in accounts to associate the account names with each account type entry.
+ Account[] accounts = mAccountManager.getAccounts();
+ for (Account account : accounts) {
+ boolean syncable =
+ ContentResolver.getIsSyncable(account, ContactsContract.AUTHORITY) > 0;
+
+ if (syncable) {
+ List<AccountType> accountTypes = accountTypesByType.get(account.type);
+ if (accountTypes != null) {
+ // Add an account-with-data-set entry for each account type that is
+ // authenticated by this account.
+ for (AccountType accountType : accountTypes) {
+ AccountWithDataSet accountWithDataSet = new AccountWithDataSet(
+ account.name, account.type, accountType.dataSet);
+ allAccounts.add(accountWithDataSet);
+ if (accountType.areContactsWritable()) {
+ contactWritableAccounts.add(accountWithDataSet);
+ }
+ if (accountType.isGroupMembershipEditable()) {
+ groupWritableAccounts.add(accountWithDataSet);
+ }
+ }
+ }
+ }
+ }
+
+ final AccountComparator accountComparator = new AccountComparator(null);
+ Collections.sort(allAccounts, accountComparator);
+ Collections.sort(contactWritableAccounts, accountComparator);
+ Collections.sort(groupWritableAccounts, accountComparator);
+
+ timings.addSplit("Loaded accounts");
+
+ synchronized (this) {
+ mAccountTypesWithDataSets = accountTypesByTypeAndDataSet;
+ mAccounts = allAccounts;
+ mContactWritableAccounts = contactWritableAccounts;
+ mGroupWritableAccounts = groupWritableAccounts;
+ mInvitableAccountTypes = findAllInvitableAccountTypes(
+ mContext, allAccounts, accountTypesByTypeAndDataSet);
+ }
+
+ timings.dumpToLog();
+ final long endTimeWall = SystemClock.elapsedRealtime();
+ final long endTime = SystemClock.currentThreadTimeMillis();
+
+ Log.i(TAG, "Loaded meta-data for " + mAccountTypesWithDataSets.size() + " account types, "
+ + mAccounts.size() + " accounts in " + (endTimeWall - startTimeWall) + "ms(wall) "
+ + (endTime - startTime) + "ms(cpu)");
+
+ if (mInitializationLatch != null) {
+ mInitializationLatch.countDown();
+ mInitializationLatch = null;
+ }
+ if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
+ Log.d(Constants.PERFORMANCE_TAG, "AccountTypeManager.loadAccountsInBackground finish");
+ }
+
+ // Check filter validity since filter may become obsolete after account update. It must be
+ // done from UI thread.
+ mMainThreadHandler.post(mCheckFilterValidityRunnable);
+ }
+
+ // Bookkeeping method for tracking the known account types in the given maps.
+ private void addAccountType(AccountType accountType,
+ Map<AccountTypeWithDataSet, AccountType> accountTypesByTypeAndDataSet,
+ Map<String, List<AccountType>> accountTypesByType) {
+ accountTypesByTypeAndDataSet.put(accountType.getAccountTypeAndDataSet(), accountType);
+ List<AccountType> accountsForType = accountTypesByType.get(accountType.accountType);
+ if (accountsForType == null) {
+ accountsForType = Lists.newArrayList();
+ }
+ accountsForType.add(accountType);
+ accountTypesByType.put(accountType.accountType, accountsForType);
+ }
+
+ /**
+ * 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;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return list of all known, contact writable {@link AccountWithDataSet}'s.
+ */
+ @Override
+ public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
+ ensureAccountsLoaded();
+ return contactWritableOnly ? mContactWritableAccounts : mAccounts;
+ }
+
+ /**
+ * Sort accounts based on default account.
+ */
+ @Override
+ public void sortAccounts(AccountWithDataSet defaultAccount) {
+ Collections.sort(mAccounts, new AccountComparator(defaultAccount));
+ Collections.sort(mContactWritableAccounts, new AccountComparator(defaultAccount));
+ Collections.sort(mGroupWritableAccounts, new AccountComparator(defaultAccount));
+ }
+
+ /**
+ * Return the list of all known, group writable {@link AccountWithDataSet}'s.
+ */
+ public List<AccountWithDataSet> getGroupWritableAccounts() {
+ ensureAccountsLoaded();
+ return mGroupWritableAccounts;
+ }
+
+ /**
+ * Find the best {@link DataKind} matching the requested
+ * {@link AccountType#accountType}, {@link AccountType#dataSet}, and {@link DataKind#mimeType}.
+ * If no direct match found, we try searching {@link FallbackAccountType}.
+ */
+ @Override
+ public DataKind getKindOrFallback(AccountType type, String mimeType) {
+ ensureAccountsLoaded();
+ DataKind kind = null;
+
+ // Try finding account type and kind matching request
+ if (type != null) {
+ kind = type.getKindForMimetype(mimeType);
+ }
+
+ if (kind == null) {
+ // Nothing found, so try fallback as last resort
+ kind = mFallbackAccountType.getKindForMimetype(mimeType);
+ }
+
+ if (kind == null) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Unknown type=" + type + ", mime=" + mimeType);
+ }
+ }
+
+ return kind;
+ }
+
+ /**
+ * Return {@link AccountType} for the given account type and data set.
+ */
+ @Override
+ public AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet) {
+ ensureAccountsLoaded();
+ synchronized (this) {
+ AccountType type = mAccountTypesWithDataSets.get(accountTypeWithDataSet);
+ return type != null ? type : mFallbackAccountType;
+ }
+ }
+
+ /**
+ * @return Unmodifiable map from {@link AccountTypeWithDataSet}s to {@link AccountType}s
+ * which support the "invite" feature and have one or more account. This is an unfiltered
+ * list. See {@link #getUsableInvitableAccountTypes()}.
+ */
+ private Map<AccountTypeWithDataSet, AccountType> getAllInvitableAccountTypes() {
+ ensureAccountsLoaded();
+ return mInvitableAccountTypes;
+ }
+
+ @Override
+ public Map<AccountTypeWithDataSet, AccountType> getUsableInvitableAccountTypes() {
+ ensureAccountsLoaded();
+ // Since this method is not thread-safe, it's possible for multiple threads to encounter
+ // the situation where (1) the cache has not been initialized yet or
+ // (2) an async task to refresh the account type list in the cache has already been
+ // started. Hence we use {@link AtomicBoolean}s and return cached values immediately
+ // while we compute the actual result in the background. We use this approach instead of
+ // using "synchronized" because computing the account type list involves a DB read, and
+ // can potentially cause a deadlock situation if this method is called from code which
+ // holds the DB lock. The trade-off of potentially having an incorrect list of invitable
+ // account types for a short period of time seems more manageable than enforcing the
+ // context in which this method is called.
+
+ // Computing the list of usable invitable account types is done on the fly as requested.
+ // If this method has never been called before, then block until the list has been computed.
+ if (!mInvitablesCacheIsInitialized.get()) {
+ mInvitableAccountTypeCache.setCachedValue(findUsableInvitableAccountTypes(mContext));
+ mInvitablesCacheIsInitialized.set(true);
+ } else {
+ // Otherwise, there is a value in the cache. If the value has expired and
+ // an async task has not already been started by another thread, then kick off a new
+ // async task to compute the list.
+ if (mInvitableAccountTypeCache.isExpired() &&
+ mInvitablesTaskIsRunning.compareAndSet(false, true)) {
+ new FindInvitablesTask().execute();
+ }
+ }
+
+ return mInvitableAccountTypeCache.getCachedValue();
+ }
+
+ /**
+ * Return all {@link AccountType}s with at least one account which supports "invite", i.e.
+ * its {@link AccountType#getInviteContactActivityClassName()} is not empty.
+ */
+ @VisibleForTesting
+ static Map<AccountTypeWithDataSet, AccountType> findAllInvitableAccountTypes(Context context,
+ Collection<AccountWithDataSet> accounts,
+ Map<AccountTypeWithDataSet, AccountType> accountTypesByTypeAndDataSet) {
+ HashMap<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap();
+ for (AccountWithDataSet account : accounts) {
+ AccountTypeWithDataSet accountTypeWithDataSet = account.getAccountTypeWithDataSet();
+ AccountType type = accountTypesByTypeAndDataSet.get(accountTypeWithDataSet);
+ if (type == null) continue; // just in case
+ if (result.containsKey(accountTypeWithDataSet)) continue;
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Type " + accountTypeWithDataSet
+ + " inviteClass=" + type.getInviteContactActivityClassName());
+ }
+ if (!TextUtils.isEmpty(type.getInviteContactActivityClassName())) {
+ result.put(accountTypeWithDataSet, type);
+ }
+ }
+ return Collections.unmodifiableMap(result);
+ }
+
+ /**
+ * Return all usable {@link AccountType}s that support the "invite" feature from the
+ * list of all potential invitable account types (retrieved from
+ * {@link #getAllInvitableAccountTypes}). A usable invitable account type means:
+ * (1) there is at least 1 raw contact in the database with that account type, and
+ * (2) the app contributing the account type is not disabled.
+ *
+ * Warning: Don't use on the UI thread because this can scan the database.
+ */
+ private Map<AccountTypeWithDataSet, AccountType> findUsableInvitableAccountTypes(
+ Context context) {
+ Map<AccountTypeWithDataSet, AccountType> allInvitables = getAllInvitableAccountTypes();
+ if (allInvitables.isEmpty()) {
+ return EMPTY_UNMODIFIABLE_ACCOUNT_TYPE_MAP;
+ }
+
+ final HashMap<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap();
+ result.putAll(allInvitables);
+
+ final PackageManager packageManager = context.getPackageManager();
+ for (AccountTypeWithDataSet accountTypeWithDataSet : allInvitables.keySet()) {
+ AccountType accountType = allInvitables.get(accountTypeWithDataSet);
+
+ // Make sure that account types don't come from apps that are disabled.
+ Intent invitableIntent = MoreContactUtils.getInvitableIntent(accountType,
+ SAMPLE_CONTACT_URI);
+ if (invitableIntent == null) {
+ result.remove(accountTypeWithDataSet);
+ continue;
+ }
+ ResolveInfo resolveInfo = packageManager.resolveActivity(invitableIntent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ if (resolveInfo == null) {
+ // If we can't find an activity to start for this intent, then there's no point in
+ // showing this option to the user.
+ result.remove(accountTypeWithDataSet);
+ continue;
+ }
+
+ // Make sure that there is at least 1 raw contact with this account type. This check
+ // is non-trivial and should not be done on the UI thread.
+ if (!accountTypeWithDataSet.hasData(context)) {
+ result.remove(accountTypeWithDataSet);
+ }
+ }
+
+ return Collections.unmodifiableMap(result);
+ }
+
+ @Override
+ public List<AccountType> getAccountTypes(boolean contactWritableOnly) {
+ ensureAccountsLoaded();
+ final List<AccountType> accountTypes = Lists.newArrayList();
+ synchronized (this) {
+ for (AccountType type : mAccountTypesWithDataSets.values()) {
+ if (!contactWritableOnly || type.areContactsWritable()) {
+ accountTypes.add(type);
+ }
+ }
+ }
+ return accountTypes;
+ }
+
+ /**
+ * Background task to find all usable {@link AccountType}s that support the "invite" feature
+ * from the list of all potential invitable account types. Once the work is completed,
+ * the list of account types is stored in the {@link AccountTypeManager}'s
+ * {@link InvitableAccountTypeCache}.
+ */
+ private class FindInvitablesTask extends AsyncTask<Void, Void,
+ Map<AccountTypeWithDataSet, AccountType>> {
+
+ @Override
+ protected Map<AccountTypeWithDataSet, AccountType> doInBackground(Void... params) {
+ return findUsableInvitableAccountTypes(mContext);
+ }
+
+ @Override
+ protected void onPostExecute(Map<AccountTypeWithDataSet, AccountType> accountTypes) {
+ mInvitableAccountTypeCache.setCachedValue(accountTypes);
+ mInvitablesTaskIsRunning.set(false);
+ }
+ }
+
+ /**
+ * This cache holds a list of invitable {@link AccountTypeWithDataSet}s, in the form of a
+ * {@link Map<AccountTypeWithDataSet, AccountType>}. Note that the cached value is valid only
+ * for {@link #TIME_TO_LIVE} milliseconds.
+ */
+ private static final class InvitableAccountTypeCache {
+
+ /**
+ * The cached {@link #mInvitableAccountTypes} list expires after this number of milliseconds
+ * has elapsed.
+ */
+ private static final long TIME_TO_LIVE = 60000;
+
+ private Map<AccountTypeWithDataSet, AccountType> mInvitableAccountTypes;
+
+ private long mTimeLastSet;
+
+ /**
+ * Returns true if the data in this cache is stale and needs to be refreshed. Returns false
+ * otherwise.
+ */
+ public boolean isExpired() {
+ return SystemClock.elapsedRealtime() - mTimeLastSet > TIME_TO_LIVE;
+ }
+
+ /**
+ * Returns the cached value. Note that the caller is responsible for checking
+ * {@link #isExpired()} to ensure that the value is not stale.
+ */
+ public Map<AccountTypeWithDataSet, AccountType> getCachedValue() {
+ return mInvitableAccountTypes;
+ }
+
+ public void setCachedValue(Map<AccountTypeWithDataSet, AccountType> map) {
+ mInvitableAccountTypes = map;
+ mTimeLastSet = SystemClock.elapsedRealtime();
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/model/BuilderWrapper.java b/src/com/android/contacts/common/model/BuilderWrapper.java
new file mode 100644
index 0000000..325c3df
--- /dev/null
+++ b/src/com/android/contacts/common/model/BuilderWrapper.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 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.common.model;
+
+import android.content.ContentProviderOperation.Builder;
+
+/**
+ * This class is created for the purpose of compatibility and make the type of
+ * ContentProviderOperation available on pre-M SDKs. Since ContentProviderOperation is
+ * usually created by Builder and we don’t have access to the type via Builder, so we need to
+ * create a wrapper class for Builder first and include type. Then we could use the builder and
+ * the type in this class to create a wrapper of ContentProviderOperation.
+ */
+public class BuilderWrapper {
+ private Builder mBuilder;
+ private int mType;
+
+ public BuilderWrapper(Builder builder, int type) {
+ mBuilder = builder;
+ mType = type;
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public void setType(int mType) {
+ this.mType = mType;
+ }
+
+ public Builder getBuilder() {
+ return mBuilder;
+ }
+
+ public void setBuilder(Builder mBuilder) {
+ this.mBuilder = mBuilder;
+ }
+}
diff --git a/src/com/android/contacts/common/model/CPOWrapper.java b/src/com/android/contacts/common/model/CPOWrapper.java
new file mode 100644
index 0000000..4124df8
--- /dev/null
+++ b/src/com/android/contacts/common/model/CPOWrapper.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 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.common.model;
+
+import android.content.ContentProviderOperation;
+
+/**
+ * This class is created for the purpose of compatibility and make the type of
+ * ContentProviderOperation available on pre-M SDKs.
+ */
+public class CPOWrapper {
+ private ContentProviderOperation mOperation;
+ private int mType;
+
+ public CPOWrapper(ContentProviderOperation builder, int type) {
+ mOperation = builder;
+ mType = type;
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public void setType(int type) {
+ this.mType = type;
+ }
+
+ public ContentProviderOperation getOperation() {
+ return mOperation;
+ }
+
+ public void setOperation(ContentProviderOperation operation) {
+ this.mOperation = operation;
+ }
+}
diff --git a/src/com/android/contacts/common/model/Contact.java b/src/com/android/contacts/common/model/Contact.java
new file mode 100644
index 0000000..27bf13e
--- /dev/null
+++ b/src/com/android/contacts/common/model/Contact.java
@@ -0,0 +1,496 @@
+/*
+ * Copyright (C) 2012 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.common.model;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.DisplayNameSources;
+
+import com.android.contacts.common.GroupMetaData;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.util.DataStatus;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * A Contact represents a single person or logical entity as perceived by the user. The information
+ * about a contact can come from multiple data sources, which are each represented by a RawContact
+ * object. Thus, a Contact is associated with a collection of RawContact objects.
+ *
+ * The aggregation of raw contacts into a single contact is performed automatically, and it is
+ * also possible for users to manually split and join raw contacts into various contacts.
+ *
+ * Only the {@link ContactLoader} class can create a Contact object with various flags to allow
+ * partial loading of contact data. Thus, an instance of this class should be treated as
+ * a read-only object.
+ */
+public class Contact {
+ private enum Status {
+ /** Contact is successfully loaded */
+ LOADED,
+ /** There was an error loading the contact */
+ ERROR,
+ /** Contact is not found */
+ NOT_FOUND,
+ }
+
+ private final Uri mRequestedUri;
+ private final Uri mLookupUri;
+ private final Uri mUri;
+ private final long mDirectoryId;
+ private final String mLookupKey;
+ private final long mId;
+ private final long mNameRawContactId;
+ private final int mDisplayNameSource;
+ private final long mPhotoId;
+ private final String mPhotoUri;
+ private final String mDisplayName;
+ private final String mAltDisplayName;
+ private final String mPhoneticName;
+ private final boolean mStarred;
+ private final Integer mPresence;
+ private ImmutableList<RawContact> mRawContacts;
+ private ImmutableMap<Long,DataStatus> mStatuses;
+ private ImmutableList<AccountType> mInvitableAccountTypes;
+
+ private String mDirectoryDisplayName;
+ private String mDirectoryType;
+ private String mDirectoryAccountType;
+ private String mDirectoryAccountName;
+ private int mDirectoryExportSupport;
+
+ private ImmutableList<GroupMetaData> mGroups;
+
+ private byte[] mPhotoBinaryData;
+ /**
+ * Small version of the contact photo loaded from a blob instead of from a file. If a large
+ * contact photo is not available yet, then this has the same value as mPhotoBinaryData.
+ */
+ private byte[] mThumbnailPhotoBinaryData;
+ private final boolean mSendToVoicemail;
+ private final String mCustomRingtone;
+ private final boolean mIsUserProfile;
+
+ private final Contact.Status mStatus;
+ private final Exception mException;
+
+ /**
+ * Constructor for special results, namely "no contact found" and "error".
+ */
+ private Contact(Uri requestedUri, Contact.Status status, Exception exception) {
+ if (status == Status.ERROR && exception == null) {
+ throw new IllegalArgumentException("ERROR result must have exception");
+ }
+ mStatus = status;
+ mException = exception;
+ mRequestedUri = requestedUri;
+ mLookupUri = null;
+ mUri = null;
+ mDirectoryId = -1;
+ mLookupKey = null;
+ mId = -1;
+ mRawContacts = null;
+ mStatuses = null;
+ mNameRawContactId = -1;
+ mDisplayNameSource = DisplayNameSources.UNDEFINED;
+ mPhotoId = -1;
+ mPhotoUri = null;
+ mDisplayName = null;
+ mAltDisplayName = null;
+ mPhoneticName = null;
+ mStarred = false;
+ mPresence = null;
+ mInvitableAccountTypes = null;
+ mSendToVoicemail = false;
+ mCustomRingtone = null;
+ mIsUserProfile = false;
+ }
+
+ public static Contact forError(Uri requestedUri, Exception exception) {
+ return new Contact(requestedUri, Status.ERROR, exception);
+ }
+
+ public static Contact forNotFound(Uri requestedUri) {
+ return new Contact(requestedUri, Status.NOT_FOUND, null);
+ }
+
+ /**
+ * Constructor to call when contact was found
+ */
+ public Contact(Uri requestedUri, Uri uri, Uri lookupUri, long directoryId, String lookupKey,
+ long id, long nameRawContactId, int displayNameSource, long photoId,
+ String photoUri, String displayName, String altDisplayName, String phoneticName,
+ boolean starred, Integer presence, boolean sendToVoicemail, String customRingtone,
+ boolean isUserProfile) {
+ mStatus = Status.LOADED;
+ mException = null;
+ mRequestedUri = requestedUri;
+ mLookupUri = lookupUri;
+ mUri = uri;
+ mDirectoryId = directoryId;
+ mLookupKey = lookupKey;
+ mId = id;
+ mRawContacts = null;
+ mStatuses = null;
+ mNameRawContactId = nameRawContactId;
+ mDisplayNameSource = displayNameSource;
+ mPhotoId = photoId;
+ mPhotoUri = photoUri;
+ mDisplayName = displayName;
+ mAltDisplayName = altDisplayName;
+ mPhoneticName = phoneticName;
+ mStarred = starred;
+ mPresence = presence;
+ mInvitableAccountTypes = null;
+ mSendToVoicemail = sendToVoicemail;
+ mCustomRingtone = customRingtone;
+ mIsUserProfile = isUserProfile;
+ }
+
+ public Contact(Uri requestedUri, Contact from) {
+ mRequestedUri = requestedUri;
+
+ mStatus = from.mStatus;
+ mException = from.mException;
+ mLookupUri = from.mLookupUri;
+ mUri = from.mUri;
+ mDirectoryId = from.mDirectoryId;
+ mLookupKey = from.mLookupKey;
+ mId = from.mId;
+ mNameRawContactId = from.mNameRawContactId;
+ mDisplayNameSource = from.mDisplayNameSource;
+ mPhotoId = from.mPhotoId;
+ mPhotoUri = from.mPhotoUri;
+ mDisplayName = from.mDisplayName;
+ mAltDisplayName = from.mAltDisplayName;
+ mPhoneticName = from.mPhoneticName;
+ mStarred = from.mStarred;
+ mPresence = from.mPresence;
+ mRawContacts = from.mRawContacts;
+ mStatuses = from.mStatuses;
+ mInvitableAccountTypes = from.mInvitableAccountTypes;
+
+ mDirectoryDisplayName = from.mDirectoryDisplayName;
+ mDirectoryType = from.mDirectoryType;
+ mDirectoryAccountType = from.mDirectoryAccountType;
+ mDirectoryAccountName = from.mDirectoryAccountName;
+ mDirectoryExportSupport = from.mDirectoryExportSupport;
+
+ mGroups = from.mGroups;
+
+ mPhotoBinaryData = from.mPhotoBinaryData;
+ mSendToVoicemail = from.mSendToVoicemail;
+ mCustomRingtone = from.mCustomRingtone;
+ mIsUserProfile = from.mIsUserProfile;
+ }
+
+ /**
+ * @param exportSupport See {@link Directory#EXPORT_SUPPORT}.
+ */
+ public void setDirectoryMetaData(String displayName, String directoryType,
+ String accountType, String accountName, int exportSupport) {
+ mDirectoryDisplayName = displayName;
+ mDirectoryType = directoryType;
+ mDirectoryAccountType = accountType;
+ mDirectoryAccountName = accountName;
+ mDirectoryExportSupport = exportSupport;
+ }
+
+ /* package */ void setPhotoBinaryData(byte[] photoBinaryData) {
+ mPhotoBinaryData = photoBinaryData;
+ }
+
+ /* package */ void setThumbnailPhotoBinaryData(byte[] photoBinaryData) {
+ mThumbnailPhotoBinaryData = photoBinaryData;
+ }
+
+ /**
+ * Returns the URI for the contact that contains both the lookup key and the ID. This is
+ * the best URI to reference a contact.
+ * For directory contacts, this is the same a the URI as returned by {@link #getUri()}
+ */
+ public Uri getLookupUri() {
+ return mLookupUri;
+ }
+
+ public String getLookupKey() {
+ return mLookupKey;
+ }
+
+ /**
+ * Returns the contact Uri that was passed to the provider to make the query. This is
+ * the same as the requested Uri, unless the requested Uri doesn't specify a Contact:
+ * If it either references a Raw-Contact or a Person (a pre-Eclair style Uri), this Uri will
+ * always reference the full aggregate contact.
+ */
+ public Uri getUri() {
+ return mUri;
+ }
+
+ /**
+ * Returns the URI for which this {@link ContactLoader) was initially requested.
+ */
+ public Uri getRequestedUri() {
+ return mRequestedUri;
+ }
+
+ /**
+ * Instantiate a new RawContactDeltaList for this contact.
+ */
+ public RawContactDeltaList createRawContactDeltaList() {
+ return RawContactDeltaList.fromIterator(getRawContacts().iterator());
+ }
+
+ /**
+ * Returns the contact ID.
+ */
+ @VisibleForTesting
+ public long getId() {
+ return mId;
+ }
+
+ /**
+ * @return true when an exception happened during loading, in which case
+ * {@link #getException} returns the actual exception object.
+ * Note {@link #isNotFound()} and {@link #isError()} are mutually exclusive; If
+ * {@link #isError()} is {@code true}, {@link #isNotFound()} is always {@code false},
+ * and vice versa.
+ */
+ public boolean isError() {
+ return mStatus == Status.ERROR;
+ }
+
+ public Exception getException() {
+ return mException;
+ }
+
+ /**
+ * @return true when the specified contact is not found.
+ * Note {@link #isNotFound()} and {@link #isError()} are mutually exclusive; If
+ * {@link #isError()} is {@code true}, {@link #isNotFound()} is always {@code false},
+ * and vice versa.
+ */
+ public boolean isNotFound() {
+ return mStatus == Status.NOT_FOUND;
+ }
+
+ /**
+ * @return true if the specified contact is successfully loaded.
+ * i.e. neither {@link #isError()} nor {@link #isNotFound()}.
+ */
+ public boolean isLoaded() {
+ return mStatus == Status.LOADED;
+ }
+
+ public long getNameRawContactId() {
+ return mNameRawContactId;
+ }
+
+ public int getDisplayNameSource() {
+ return mDisplayNameSource;
+ }
+
+ /**
+ * Used by various classes to determine whether or not this contact should be displayed as
+ * a business rather than a person.
+ */
+ public boolean isDisplayNameFromOrganization() {
+ return DisplayNameSources.ORGANIZATION == mDisplayNameSource;
+ }
+
+ public long getPhotoId() {
+ return mPhotoId;
+ }
+
+ public String getPhotoUri() {
+ return mPhotoUri;
+ }
+
+ public String getDisplayName() {
+ return mDisplayName;
+ }
+
+ public String getAltDisplayName() {
+ return mAltDisplayName;
+ }
+
+ public String getPhoneticName() {
+ return mPhoneticName;
+ }
+
+ public boolean getStarred() {
+ return mStarred;
+ }
+
+ public Integer getPresence() {
+ return mPresence;
+ }
+
+ /**
+ * This can return non-null invitable account types only if the {@link ContactLoader} was
+ * configured to load invitable account types in its constructor.
+ * @return
+ */
+ public ImmutableList<AccountType> getInvitableAccountTypes() {
+ return mInvitableAccountTypes;
+ }
+
+ public ImmutableList<RawContact> getRawContacts() {
+ return mRawContacts;
+ }
+
+ public ImmutableMap<Long, DataStatus> getStatuses() {
+ return mStatuses;
+ }
+
+ public long getDirectoryId() {
+ return mDirectoryId;
+ }
+
+ public boolean isDirectoryEntry() {
+ return mDirectoryId != -1 && mDirectoryId != Directory.DEFAULT
+ && mDirectoryId != Directory.LOCAL_INVISIBLE;
+ }
+
+ /**
+ * @return true if this is a contact (not group, etc.) with at least one
+ * writable raw-contact, and false otherwise.
+ */
+ public boolean isWritableContact(final Context context) {
+ return getFirstWritableRawContactId(context) != -1;
+ }
+
+ /**
+ * Return the ID of the first raw-contact in the contact data that belongs to a
+ * contact-writable account, or -1 if no such entity exists.
+ */
+ public long getFirstWritableRawContactId(final Context context) {
+ // Directory entries are non-writable
+ if (isDirectoryEntry()) return -1;
+
+ // Iterate through raw-contacts; if we find a writable on, return its ID.
+ for (RawContact rawContact : getRawContacts()) {
+ AccountType accountType = rawContact.getAccountType(context);
+ if (accountType != null && accountType.areContactsWritable()) {
+ return rawContact.getId();
+ }
+ }
+ // No writable raw-contact was found.
+ return -1;
+ }
+
+ public int getDirectoryExportSupport() {
+ return mDirectoryExportSupport;
+ }
+
+ public String getDirectoryDisplayName() {
+ return mDirectoryDisplayName;
+ }
+
+ public String getDirectoryType() {
+ return mDirectoryType;
+ }
+
+ public String getDirectoryAccountType() {
+ return mDirectoryAccountType;
+ }
+
+ public String getDirectoryAccountName() {
+ return mDirectoryAccountName;
+ }
+
+ public byte[] getPhotoBinaryData() {
+ return mPhotoBinaryData;
+ }
+
+ public byte[] getThumbnailPhotoBinaryData() {
+ return mThumbnailPhotoBinaryData;
+ }
+
+ public ArrayList<ContentValues> getContentValues() {
+ if (mRawContacts.size() != 1) {
+ throw new IllegalStateException(
+ "Cannot extract content values from an aggregated contact");
+ }
+
+ RawContact rawContact = mRawContacts.get(0);
+ ArrayList<ContentValues> result = rawContact.getContentValues();
+
+ // If the photo was loaded using the URI, create an entry for the photo
+ // binary data.
+ if (mPhotoId == 0 && mPhotoBinaryData != null) {
+ ContentValues photo = new ContentValues();
+ photo.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
+ photo.put(Photo.PHOTO, mPhotoBinaryData);
+ result.add(photo);
+ }
+
+ return result;
+ }
+
+ /**
+ * This can return non-null group meta-data only if the {@link ContactLoader} was configured to
+ * load group metadata in its constructor.
+ * @return
+ */
+ public ImmutableList<GroupMetaData> getGroupMetaData() {
+ return mGroups;
+ }
+
+ public boolean isSendToVoicemail() {
+ return mSendToVoicemail;
+ }
+
+ public String getCustomRingtone() {
+ return mCustomRingtone;
+ }
+
+ public boolean isUserProfile() {
+ return mIsUserProfile;
+ }
+
+ @Override
+ public String toString() {
+ return "{requested=" + mRequestedUri + ",lookupkey=" + mLookupKey +
+ ",uri=" + mUri + ",status=" + mStatus + "}";
+ }
+
+ /* package */ void setRawContacts(ImmutableList<RawContact> rawContacts) {
+ mRawContacts = rawContacts;
+ }
+
+ /* package */ void setStatuses(ImmutableMap<Long, DataStatus> statuses) {
+ mStatuses = statuses;
+ }
+
+ /* package */ void setInvitableAccountTypes(ImmutableList<AccountType> accountTypes) {
+ mInvitableAccountTypes = accountTypes;
+ }
+
+ /* package */ void setGroupMetaData(ImmutableList<GroupMetaData> groups) {
+ mGroups = groups;
+ }
+}
diff --git a/src/com/android/contacts/common/model/ContactLoader.java b/src/com/android/contacts/common/model/ContactLoader.java
new file mode 100644
index 0000000..f721379
--- /dev/null
+++ b/src/com/android/contacts/common/model/ContactLoader.java
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (C) 2010 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.common.model;
+
+import android.content.AsyncTaskLoader;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.Groups;
+import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.contacts.common.GeoUtil;
+import com.android.contacts.common.GroupMetaData;
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountTypeWithDataSet;
+import com.android.contacts.common.util.Constants;
+import com.android.contacts.common.util.ContactLoaderUtils;
+import com.android.contacts.common.util.DataStatus;
+import com.android.contacts.common.util.UriUtils;
+import com.android.contacts.common.model.dataitem.DataItem;
+import com.android.contacts.common.model.dataitem.PhoneDataItem;
+import com.android.contacts.common.model.dataitem.PhotoDataItem;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Loads a single Contact and all it constituent RawContacts.
+ */
+public class ContactLoader extends AsyncTaskLoader<Contact> {
+
+ private static final String TAG = ContactLoader.class.getSimpleName();
+
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ /** A short-lived cache that can be set by {@link #cacheResult()} */
+ private static Contact sCachedResult = null;
+
+ private final Uri mRequestedUri;
+ private Uri mLookupUri;
+ private boolean mLoadGroupMetaData;
+ private boolean mLoadInvitableAccountTypes;
+ private boolean mPostViewNotification;
+ private boolean mComputeFormattedPhoneNumber;
+ private Contact mContact;
+ private ForceLoadContentObserver mObserver;
+ private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet();
+
+ public ContactLoader(Context context, Uri lookupUri, boolean postViewNotification) {
+ this(context, lookupUri, false, false, postViewNotification, false);
+ }
+
+ public ContactLoader(Context context, Uri lookupUri, boolean loadGroupMetaData,
+ boolean loadInvitableAccountTypes,
+ boolean postViewNotification, boolean computeFormattedPhoneNumber) {
+ super(context);
+ mLookupUri = lookupUri;
+ mRequestedUri = lookupUri;
+ mLoadGroupMetaData = loadGroupMetaData;
+ mLoadInvitableAccountTypes = loadInvitableAccountTypes;
+ mPostViewNotification = postViewNotification;
+ mComputeFormattedPhoneNumber = computeFormattedPhoneNumber;
+ }
+
+ /**
+ * Projection used for the query that loads all data for the entire contact (except for
+ * social stream items).
+ */
+ private static class ContactQuery {
+ static final String[] COLUMNS_INTERNAL = new String[] {
+ Contacts.NAME_RAW_CONTACT_ID,
+ Contacts.DISPLAY_NAME_SOURCE,
+ Contacts.LOOKUP_KEY,
+ Contacts.DISPLAY_NAME,
+ Contacts.DISPLAY_NAME_ALTERNATIVE,
+ Contacts.PHONETIC_NAME,
+ Contacts.PHOTO_ID,
+ Contacts.STARRED,
+ Contacts.CONTACT_PRESENCE,
+ Contacts.CONTACT_STATUS,
+ Contacts.CONTACT_STATUS_TIMESTAMP,
+ Contacts.CONTACT_STATUS_RES_PACKAGE,
+ Contacts.CONTACT_STATUS_LABEL,
+ Contacts.Entity.CONTACT_ID,
+ Contacts.Entity.RAW_CONTACT_ID,
+
+ RawContacts.ACCOUNT_NAME,
+ RawContacts.ACCOUNT_TYPE,
+ RawContacts.DATA_SET,
+ RawContacts.DIRTY,
+ RawContacts.VERSION,
+ RawContacts.SOURCE_ID,
+ RawContacts.SYNC1,
+ RawContacts.SYNC2,
+ RawContacts.SYNC3,
+ RawContacts.SYNC4,
+ RawContacts.DELETED,
+
+ Contacts.Entity.DATA_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,
+ Data.SYNC1,
+ Data.SYNC2,
+ Data.SYNC3,
+ Data.SYNC4,
+ Data.DATA_VERSION,
+ Data.IS_PRIMARY,
+ Data.IS_SUPER_PRIMARY,
+ Data.MIMETYPE,
+
+ GroupMembership.GROUP_SOURCE_ID,
+
+ Data.PRESENCE,
+ Data.CHAT_CAPABILITY,
+ Data.STATUS,
+ Data.STATUS_RES_PACKAGE,
+ Data.STATUS_ICON,
+ Data.STATUS_LABEL,
+ Data.STATUS_TIMESTAMP,
+
+ Contacts.PHOTO_URI,
+ Contacts.SEND_TO_VOICEMAIL,
+ Contacts.CUSTOM_RINGTONE,
+ Contacts.IS_USER_PROFILE,
+
+ Data.TIMES_USED,
+ Data.LAST_TIME_USED
+ };
+
+ static final String[] COLUMNS;
+
+ static {
+ List<String> projectionList = Lists.newArrayList(COLUMNS_INTERNAL);
+ if (CompatUtils.isMarshmallowCompatible()) {
+ projectionList.add(Data.CARRIER_PRESENCE);
+ }
+ COLUMNS = projectionList.toArray(new String[projectionList.size()]);
+ }
+
+ public static final int NAME_RAW_CONTACT_ID = 0;
+ public static final int DISPLAY_NAME_SOURCE = 1;
+ public static final int LOOKUP_KEY = 2;
+ public static final int DISPLAY_NAME = 3;
+ public static final int ALT_DISPLAY_NAME = 4;
+ public static final int PHONETIC_NAME = 5;
+ public static final int PHOTO_ID = 6;
+ public static final int STARRED = 7;
+ public static final int CONTACT_PRESENCE = 8;
+ public static final int CONTACT_STATUS = 9;
+ public static final int CONTACT_STATUS_TIMESTAMP = 10;
+ public static final int CONTACT_STATUS_RES_PACKAGE = 11;
+ public static final int CONTACT_STATUS_LABEL = 12;
+ public static final int CONTACT_ID = 13;
+ public static final int RAW_CONTACT_ID = 14;
+
+ public static final int ACCOUNT_NAME = 15;
+ public static final int ACCOUNT_TYPE = 16;
+ public static final int DATA_SET = 17;
+ public static final int DIRTY = 18;
+ public static final int VERSION = 19;
+ public static final int SOURCE_ID = 20;
+ public static final int SYNC1 = 21;
+ public static final int SYNC2 = 22;
+ public static final int SYNC3 = 23;
+ public static final int SYNC4 = 24;
+ public static final int DELETED = 25;
+
+ public static final int DATA_ID = 26;
+ public static final int DATA1 = 27;
+ public static final int DATA2 = 28;
+ public static final int DATA3 = 29;
+ public static final int DATA4 = 30;
+ public static final int DATA5 = 31;
+ public static final int DATA6 = 32;
+ public static final int DATA7 = 33;
+ public static final int DATA8 = 34;
+ public static final int DATA9 = 35;
+ public static final int DATA10 = 36;
+ public static final int DATA11 = 37;
+ public static final int DATA12 = 38;
+ public static final int DATA13 = 39;
+ public static final int DATA14 = 40;
+ public static final int DATA15 = 41;
+ public static final int DATA_SYNC1 = 42;
+ public static final int DATA_SYNC2 = 43;
+ public static final int DATA_SYNC3 = 44;
+ public static final int DATA_SYNC4 = 45;
+ public static final int DATA_VERSION = 46;
+ public static final int IS_PRIMARY = 47;
+ public static final int IS_SUPERPRIMARY = 48;
+ public static final int MIMETYPE = 49;
+
+ public static final int GROUP_SOURCE_ID = 50;
+
+ public static final int PRESENCE = 51;
+ public static final int CHAT_CAPABILITY = 52;
+ public static final int STATUS = 53;
+ public static final int STATUS_RES_PACKAGE = 54;
+ public static final int STATUS_ICON = 55;
+ public static final int STATUS_LABEL = 56;
+ public static final int STATUS_TIMESTAMP = 57;
+
+ public static final int PHOTO_URI = 58;
+ public static final int SEND_TO_VOICEMAIL = 59;
+ public static final int CUSTOM_RINGTONE = 60;
+ public static final int IS_USER_PROFILE = 61;
+
+ public static final int TIMES_USED = 62;
+ public static final int LAST_TIME_USED = 63;
+ public static final int CARRIER_PRESENCE = 64;
+ }
+
+ /**
+ * Projection used for the query that loads all data for the entire contact.
+ */
+ private static class DirectoryQuery {
+ static final String[] COLUMNS = new String[] {
+ Directory.DISPLAY_NAME,
+ Directory.PACKAGE_NAME,
+ Directory.TYPE_RESOURCE_ID,
+ Directory.ACCOUNT_TYPE,
+ Directory.ACCOUNT_NAME,
+ Directory.EXPORT_SUPPORT,
+ };
+
+ public static final int DISPLAY_NAME = 0;
+ public static final int PACKAGE_NAME = 1;
+ public static final int TYPE_RESOURCE_ID = 2;
+ public static final int ACCOUNT_TYPE = 3;
+ public static final int ACCOUNT_NAME = 4;
+ public static final int EXPORT_SUPPORT = 5;
+ }
+
+ private static class GroupQuery {
+ static final String[] COLUMNS = new String[] {
+ Groups.ACCOUNT_NAME,
+ Groups.ACCOUNT_TYPE,
+ Groups.DATA_SET,
+ Groups._ID,
+ Groups.TITLE,
+ Groups.AUTO_ADD,
+ Groups.FAVORITES,
+ };
+
+ public static final int ACCOUNT_NAME = 0;
+ public static final int ACCOUNT_TYPE = 1;
+ public static final int DATA_SET = 2;
+ public static final int ID = 3;
+ public static final int TITLE = 4;
+ public static final int AUTO_ADD = 5;
+ public static final int FAVORITES = 6;
+ }
+
+ public void setLookupUri(Uri lookupUri) {
+ mLookupUri = lookupUri;
+ }
+
+ @Override
+ public Contact loadInBackground() {
+ Log.e(TAG, "loadInBackground=" + mLookupUri);
+ try {
+ final ContentResolver resolver = getContext().getContentResolver();
+ final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(
+ resolver, mLookupUri);
+ final Contact cachedResult = sCachedResult;
+ sCachedResult = null;
+ // Is this the same Uri as what we had before already? In that case, reuse that result
+ final Contact result;
+ final boolean resultIsCached;
+ if (cachedResult != null &&
+ UriUtils.areEqual(cachedResult.getLookupUri(), mLookupUri)) {
+ // We are using a cached result from earlier. Below, we should make sure
+ // we are not doing any more network or disc accesses
+ result = new Contact(mRequestedUri, cachedResult);
+ resultIsCached = true;
+ } else {
+ if (uriCurrentFormat.getLastPathSegment().equals(Constants.LOOKUP_URI_ENCODED)) {
+ result = loadEncodedContactEntity(uriCurrentFormat, mLookupUri);
+ } else {
+ result = loadContactEntity(resolver, uriCurrentFormat);
+ }
+ resultIsCached = false;
+ }
+ if (result.isLoaded()) {
+ if (result.isDirectoryEntry()) {
+ if (!resultIsCached) {
+ loadDirectoryMetaData(result);
+ }
+ } else if (mLoadGroupMetaData) {
+ if (result.getGroupMetaData() == null) {
+ loadGroupMetaData(result);
+ }
+ }
+ if (mComputeFormattedPhoneNumber) {
+ computeFormattedPhoneNumbers(result);
+ }
+ if (!resultIsCached) loadPhotoBinaryData(result);
+
+ // Note ME profile should never have "Add connection"
+ if (mLoadInvitableAccountTypes && result.getInvitableAccountTypes() == null) {
+ loadInvitableAccountTypes(result);
+ }
+ }
+ return result;
+ } catch (Exception e) {
+ Log.e(TAG, "Error loading the contact: " + mLookupUri, e);
+ return Contact.forError(mRequestedUri, e);
+ }
+ }
+
+ /**
+ * Parses a {@link Contact} stored as a JSON string in a lookup URI.
+ *
+ * @param lookupUri The contact information to parse .
+ * @return The parsed {@code Contact} information.
+ * @throws JSONException
+ */
+ public static Contact parseEncodedContactEntity(Uri lookupUri) {
+ try {
+ return loadEncodedContactEntity(lookupUri, lookupUri);
+ } catch (JSONException je) {
+ return null;
+ }
+ }
+
+ private static Contact loadEncodedContactEntity(Uri uri, Uri lookupUri) throws JSONException {
+ final String jsonString = uri.getEncodedFragment();
+ final JSONObject json = new JSONObject(jsonString);
+
+ final long directoryId =
+ Long.valueOf(uri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY));
+
+ final String displayName = json.optString(Contacts.DISPLAY_NAME);
+ final String altDisplayName = json.optString(
+ Contacts.DISPLAY_NAME_ALTERNATIVE, displayName);
+ final int displayNameSource = json.getInt(Contacts.DISPLAY_NAME_SOURCE);
+ final String photoUri = json.optString(Contacts.PHOTO_URI, null);
+ final Contact contact = new Contact(
+ uri, uri,
+ lookupUri,
+ directoryId,
+ null /* lookupKey */,
+ -1 /* id */,
+ -1 /* nameRawContactId */,
+ displayNameSource,
+ 0 /* photoId */,
+ photoUri,
+ displayName,
+ altDisplayName,
+ null /* phoneticName */,
+ false /* starred */,
+ null /* presence */,
+ false /* sendToVoicemail */,
+ null /* customRingtone */,
+ false /* isUserProfile */);
+
+ contact.setStatuses(new ImmutableMap.Builder<Long, DataStatus>().build());
+
+ final String accountName = json.optString(RawContacts.ACCOUNT_NAME, null);
+ final String directoryName = uri.getQueryParameter(Directory.DISPLAY_NAME);
+ if (accountName != null) {
+ final String accountType = json.getString(RawContacts.ACCOUNT_TYPE);
+ contact.setDirectoryMetaData(directoryName, null, accountName, accountType,
+ json.optInt(Directory.EXPORT_SUPPORT,
+ Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY));
+ } else {
+ contact.setDirectoryMetaData(directoryName, null, null, null,
+ json.optInt(Directory.EXPORT_SUPPORT, Directory.EXPORT_SUPPORT_ANY_ACCOUNT));
+ }
+
+ final ContentValues values = new ContentValues();
+ values.put(Data._ID, -1);
+ values.put(Data.CONTACT_ID, -1);
+ final RawContact rawContact = new RawContact(values);
+
+ final JSONObject items = json.getJSONObject(Contacts.CONTENT_ITEM_TYPE);
+ final Iterator keys = items.keys();
+ while (keys.hasNext()) {
+ final String mimetype = (String) keys.next();
+
+ // Could be single object or array.
+ final JSONObject obj = items.optJSONObject(mimetype);
+ if (obj == null) {
+ final JSONArray array = items.getJSONArray(mimetype);
+ for (int i = 0; i < array.length(); i++) {
+ final JSONObject item = array.getJSONObject(i);
+ processOneRecord(rawContact, item, mimetype);
+ }
+ } else {
+ processOneRecord(rawContact, obj, mimetype);
+ }
+ }
+
+ contact.setRawContacts(new ImmutableList.Builder<RawContact>()
+ .add(rawContact)
+ .build());
+ return contact;
+ }
+
+ private static void processOneRecord(RawContact rawContact, JSONObject item, String mimetype)
+ throws JSONException {
+ final ContentValues itemValues = new ContentValues();
+ itemValues.put(Data.MIMETYPE, mimetype);
+ itemValues.put(Data._ID, -1);
+
+ final Iterator iterator = item.keys();
+ while (iterator.hasNext()) {
+ String name = (String) iterator.next();
+ final Object o = item.get(name);
+ if (o instanceof String) {
+ itemValues.put(name, (String) o);
+ } else if (o instanceof Integer) {
+ itemValues.put(name, (Integer) o);
+ }
+ }
+ rawContact.addDataItemValues(itemValues);
+ }
+
+ private Contact loadContactEntity(ContentResolver resolver, Uri contactUri) {
+ Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY);
+ Cursor cursor = resolver.query(entityUri, ContactQuery.COLUMNS, null, null,
+ Contacts.Entity.RAW_CONTACT_ID);
+ if (cursor == null) {
+ Log.e(TAG, "No cursor returned in loadContactEntity");
+ return Contact.forNotFound(mRequestedUri);
+ }
+
+ try {
+ if (!cursor.moveToFirst()) {
+ cursor.close();
+ return Contact.forNotFound(mRequestedUri);
+ }
+
+ // Create the loaded contact starting with the header data.
+ Contact contact = loadContactHeaderData(cursor, contactUri);
+
+ // Fill in the raw contacts, which is wrapped in an Entity and any
+ // status data. Initially, result has empty entities and statuses.
+ long currentRawContactId = -1;
+ RawContact rawContact = null;
+ ImmutableList.Builder<RawContact> rawContactsBuilder =
+ new ImmutableList.Builder<RawContact>();
+ ImmutableMap.Builder<Long, DataStatus> statusesBuilder =
+ new ImmutableMap.Builder<Long, DataStatus>();
+ do {
+ long rawContactId = cursor.getLong(ContactQuery.RAW_CONTACT_ID);
+ if (rawContactId != currentRawContactId) {
+ // First time to see this raw contact id, so create a new entity, and
+ // add it to the result's entities.
+ currentRawContactId = rawContactId;
+ rawContact = new RawContact(loadRawContactValues(cursor));
+ rawContactsBuilder.add(rawContact);
+ }
+ if (!cursor.isNull(ContactQuery.DATA_ID)) {
+ ContentValues data = loadDataValues(cursor);
+ rawContact.addDataItemValues(data);
+
+ if (!cursor.isNull(ContactQuery.PRESENCE)
+ || !cursor.isNull(ContactQuery.STATUS)) {
+ final DataStatus status = new DataStatus(cursor);
+ final long dataId = cursor.getLong(ContactQuery.DATA_ID);
+ statusesBuilder.put(dataId, status);
+ }
+ }
+ } while (cursor.moveToNext());
+
+ contact.setRawContacts(rawContactsBuilder.build());
+ contact.setStatuses(statusesBuilder.build());
+
+ return contact;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ /**
+ * Looks for the photo data item in entities. If found, a thumbnail will be stored. A larger
+ * photo will also be stored if available.
+ */
+ private void loadPhotoBinaryData(Contact contactData) {
+ loadThumbnailBinaryData(contactData);
+
+ // Try to load the large photo from a file using the photo URI.
+ String photoUri = contactData.getPhotoUri();
+ if (photoUri != null) {
+ try {
+ final InputStream inputStream;
+ final AssetFileDescriptor fd;
+ final Uri uri = Uri.parse(photoUri);
+ final String scheme = uri.getScheme();
+ if ("http".equals(scheme) || "https".equals(scheme)) {
+ // Support HTTP urls that might come from extended directories
+ inputStream = new URL(photoUri).openStream();
+ fd = null;
+ } else {
+ fd = getContext().getContentResolver().openAssetFileDescriptor(uri, "r");
+ inputStream = fd.createInputStream();
+ }
+ byte[] buffer = new byte[16 * 1024];
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ int size;
+ while ((size = inputStream.read(buffer)) != -1) {
+ baos.write(buffer, 0, size);
+ }
+ contactData.setPhotoBinaryData(baos.toByteArray());
+ } finally {
+ inputStream.close();
+ if (fd != null) {
+ fd.close();
+ }
+ }
+ return;
+ } catch (IOException ioe) {
+ // Just fall back to the case below.
+ }
+ }
+
+ // If we couldn't load from a file, fall back to the data blob.
+ contactData.setPhotoBinaryData(contactData.getThumbnailPhotoBinaryData());
+ }
+
+ private void loadThumbnailBinaryData(Contact contactData) {
+ final long photoId = contactData.getPhotoId();
+ if (photoId <= 0) {
+ // No photo ID
+ return;
+ }
+
+ for (RawContact rawContact : contactData.getRawContacts()) {
+ for (DataItem dataItem : rawContact.getDataItems()) {
+ if (dataItem.getId() == photoId) {
+ if (!(dataItem instanceof PhotoDataItem)) {
+ break;
+ }
+
+ final PhotoDataItem photo = (PhotoDataItem) dataItem;
+ contactData.setThumbnailPhotoBinaryData(photo.getPhoto());
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the "invitable" account types to {@link Contact#mInvitableAccountTypes}.
+ */
+ private void loadInvitableAccountTypes(Contact contactData) {
+ final ImmutableList.Builder<AccountType> resultListBuilder =
+ new ImmutableList.Builder<AccountType>();
+ if (!contactData.isUserProfile()) {
+ Map<AccountTypeWithDataSet, AccountType> invitables =
+ AccountTypeManager.getInstance(getContext()).getUsableInvitableAccountTypes();
+ if (!invitables.isEmpty()) {
+ final Map<AccountTypeWithDataSet, AccountType> resultMap =
+ Maps.newHashMap(invitables);
+
+ // Remove the ones that already have a raw contact in the current contact
+ for (RawContact rawContact : contactData.getRawContacts()) {
+ final AccountTypeWithDataSet type = AccountTypeWithDataSet.get(
+ rawContact.getAccountTypeString(),
+ rawContact.getDataSet());
+ resultMap.remove(type);
+ }
+
+ resultListBuilder.addAll(resultMap.values());
+ }
+ }
+
+ // Set to mInvitableAccountTypes
+ contactData.setInvitableAccountTypes(resultListBuilder.build());
+ }
+
+ /**
+ * Extracts Contact level columns from the cursor.
+ */
+ private Contact loadContactHeaderData(final Cursor cursor, Uri contactUri) {
+ final String directoryParameter =
+ contactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
+ final long directoryId = directoryParameter == null
+ ? Directory.DEFAULT
+ : Long.parseLong(directoryParameter);
+ final long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
+ final String lookupKey = cursor.getString(ContactQuery.LOOKUP_KEY);
+ final long nameRawContactId = cursor.getLong(ContactQuery.NAME_RAW_CONTACT_ID);
+ final int displayNameSource = cursor.getInt(ContactQuery.DISPLAY_NAME_SOURCE);
+ final String displayName = cursor.getString(ContactQuery.DISPLAY_NAME);
+ final String altDisplayName = cursor.getString(ContactQuery.ALT_DISPLAY_NAME);
+ final String phoneticName = cursor.getString(ContactQuery.PHONETIC_NAME);
+ final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
+ final String photoUri = cursor.getString(ContactQuery.PHOTO_URI);
+ final boolean starred = cursor.getInt(ContactQuery.STARRED) != 0;
+ final Integer presence = cursor.isNull(ContactQuery.CONTACT_PRESENCE)
+ ? null
+ : cursor.getInt(ContactQuery.CONTACT_PRESENCE);
+ final boolean sendToVoicemail = cursor.getInt(ContactQuery.SEND_TO_VOICEMAIL) == 1;
+ final String customRingtone = cursor.getString(ContactQuery.CUSTOM_RINGTONE);
+ final boolean isUserProfile = cursor.getInt(ContactQuery.IS_USER_PROFILE) == 1;
+
+ Uri lookupUri;
+ if (directoryId == Directory.DEFAULT || directoryId == Directory.LOCAL_INVISIBLE) {
+ lookupUri = ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), contactId);
+ } else {
+ lookupUri = contactUri;
+ }
+
+ return new Contact(mRequestedUri, contactUri, lookupUri, directoryId, lookupKey,
+ contactId, nameRawContactId, displayNameSource, photoId, photoUri, displayName,
+ altDisplayName, phoneticName, starred, presence, sendToVoicemail,
+ customRingtone, isUserProfile);
+ }
+
+ /**
+ * Extracts RawContact level columns from the cursor.
+ */
+ private ContentValues loadRawContactValues(Cursor cursor) {
+ ContentValues cv = new ContentValues();
+
+ cv.put(RawContacts._ID, cursor.getLong(ContactQuery.RAW_CONTACT_ID));
+
+ cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_NAME);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SET);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DIRTY);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.VERSION);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.SOURCE_ID);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC1);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC2);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC3);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC4);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DELETED);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.CONTACT_ID);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.STARRED);
+
+ return cv;
+ }
+
+ /**
+ * Extracts Data level columns from the cursor.
+ */
+ private ContentValues loadDataValues(Cursor cursor) {
+ ContentValues cv = new ContentValues();
+
+ cv.put(Data._ID, cursor.getLong(ContactQuery.DATA_ID));
+
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA1);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA2);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA3);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA4);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA5);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA6);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA7);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA8);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA9);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA10);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA11);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA12);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA13);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA14);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA15);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC1);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC2);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC3);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC4);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_VERSION);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.IS_PRIMARY);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.IS_SUPERPRIMARY);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.MIMETYPE);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.GROUP_SOURCE_ID);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.CHAT_CAPABILITY);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.TIMES_USED);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.LAST_TIME_USED);
+ if (CompatUtils.isMarshmallowCompatible()) {
+ cursorColumnToContentValues(cursor, cv, ContactQuery.CARRIER_PRESENCE);
+ }
+
+ return cv;
+ }
+
+ private void cursorColumnToContentValues(
+ Cursor cursor, ContentValues values, int index) {
+ switch (cursor.getType(index)) {
+ case Cursor.FIELD_TYPE_NULL:
+ // don't put anything in the content values
+ break;
+ case Cursor.FIELD_TYPE_INTEGER:
+ values.put(ContactQuery.COLUMNS[index], cursor.getLong(index));
+ break;
+ case Cursor.FIELD_TYPE_STRING:
+ values.put(ContactQuery.COLUMNS[index], cursor.getString(index));
+ break;
+ case Cursor.FIELD_TYPE_BLOB:
+ values.put(ContactQuery.COLUMNS[index], cursor.getBlob(index));
+ break;
+ default:
+ throw new IllegalStateException("Invalid or unhandled data type");
+ }
+ }
+
+ private void loadDirectoryMetaData(Contact result) {
+ long directoryId = result.getDirectoryId();
+
+ Cursor cursor = getContext().getContentResolver().query(
+ ContentUris.withAppendedId(Directory.CONTENT_URI, directoryId),
+ DirectoryQuery.COLUMNS, null, null, null);
+ if (cursor == null) {
+ return;
+ }
+ try {
+ if (cursor.moveToFirst()) {
+ final String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
+ final String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
+ final int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
+ final String accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE);
+ final String accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME);
+ final int exportSupport = cursor.getInt(DirectoryQuery.EXPORT_SUPPORT);
+ String directoryType = null;
+ if (!TextUtils.isEmpty(packageName)) {
+ PackageManager pm = getContext().getPackageManager();
+ try {
+ Resources resources = pm.getResourcesForApplication(packageName);
+ directoryType = resources.getString(typeResourceId);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Contact directory resource not found: "
+ + packageName + "." + typeResourceId);
+ }
+ }
+
+ result.setDirectoryMetaData(
+ displayName, directoryType, accountType, accountName, exportSupport);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ static private class AccountKey {
+ private final String mAccountName;
+ private final String mAccountType;
+ private final String mDataSet;
+
+ public AccountKey(String accountName, String accountType, String dataSet) {
+ mAccountName = accountName;
+ mAccountType = accountType;
+ mDataSet = dataSet;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAccountName, mAccountType, mDataSet);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AccountKey)) {
+ return false;
+ }
+ final AccountKey other = (AccountKey) obj;
+ return Objects.equals(mAccountName, other.mAccountName)
+ && Objects.equals(mAccountType, other.mAccountType)
+ && Objects.equals(mDataSet, other.mDataSet);
+ }
+ }
+
+ /**
+ * Loads groups meta-data for all groups associated with all constituent raw contacts'
+ * accounts.
+ */
+ private void loadGroupMetaData(Contact result) {
+ StringBuilder selection = new StringBuilder();
+ ArrayList<String> selectionArgs = new ArrayList<String>();
+ final HashSet<AccountKey> accountsSeen = new HashSet<>();
+ for (RawContact rawContact : result.getRawContacts()) {
+ final String accountName = rawContact.getAccountName();
+ final String accountType = rawContact.getAccountTypeString();
+ final String dataSet = rawContact.getDataSet();
+ final AccountKey accountKey = new AccountKey(accountName, accountType, dataSet);
+ if (accountName != null && accountType != null &&
+ !accountsSeen.contains(accountKey)) {
+ accountsSeen.add(accountKey);
+ if (selection.length() != 0) {
+ selection.append(" OR ");
+ }
+ selection.append(
+ "(" + Groups.ACCOUNT_NAME + "=? AND " + Groups.ACCOUNT_TYPE + "=?");
+ selectionArgs.add(accountName);
+ selectionArgs.add(accountType);
+
+ selection.append(" AND " + Groups.DELETED + "=0");
+
+ if (dataSet != null) {
+ selection.append(" AND " + Groups.DATA_SET + "=?");
+ selectionArgs.add(dataSet);
+ } else {
+ selection.append(" AND " + Groups.DATA_SET + " IS NULL");
+ }
+ selection.append(")");
+ }
+ }
+ final ImmutableList.Builder<GroupMetaData> groupListBuilder =
+ new ImmutableList.Builder<GroupMetaData>();
+ final Cursor cursor = getContext().getContentResolver().query(Groups.CONTENT_URI,
+ GroupQuery.COLUMNS, selection.toString(), selectionArgs.toArray(new String[0]),
+ null);
+ if (cursor != null) {
+ try {
+ while (cursor.moveToNext()) {
+ final String accountName = cursor.getString(GroupQuery.ACCOUNT_NAME);
+ final String accountType = cursor.getString(GroupQuery.ACCOUNT_TYPE);
+ final String dataSet = cursor.getString(GroupQuery.DATA_SET);
+ final long groupId = cursor.getLong(GroupQuery.ID);
+ final String title = cursor.getString(GroupQuery.TITLE);
+ final boolean defaultGroup = cursor.isNull(GroupQuery.AUTO_ADD)
+ ? false
+ : cursor.getInt(GroupQuery.AUTO_ADD) != 0;
+ final boolean favorites = cursor.isNull(GroupQuery.FAVORITES)
+ ? false
+ : cursor.getInt(GroupQuery.FAVORITES) != 0;
+
+ groupListBuilder.add(new GroupMetaData(
+ accountName, accountType, dataSet, groupId, title, defaultGroup,
+ favorites));
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ result.setGroupMetaData(groupListBuilder.build());
+ }
+
+ /**
+ * Iterates over all data items that represent phone numbers are tries to calculate a formatted
+ * number. This function can safely be called several times as no unformatted data is
+ * overwritten
+ */
+ private void computeFormattedPhoneNumbers(Contact contactData) {
+ final String countryIso = GeoUtil.getCurrentCountryIso(getContext());
+ final ImmutableList<RawContact> rawContacts = contactData.getRawContacts();
+ final int rawContactCount = rawContacts.size();
+ for (int rawContactIndex = 0; rawContactIndex < rawContactCount; rawContactIndex++) {
+ final RawContact rawContact = rawContacts.get(rawContactIndex);
+ final List<DataItem> dataItems = rawContact.getDataItems();
+ final int dataCount = dataItems.size();
+ for (int dataIndex = 0; dataIndex < dataCount; dataIndex++) {
+ final DataItem dataItem = dataItems.get(dataIndex);
+ if (dataItem instanceof PhoneDataItem) {
+ final PhoneDataItem phoneDataItem = (PhoneDataItem) dataItem;
+ phoneDataItem.computeFormattedPhoneNumber(countryIso);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void deliverResult(Contact result) {
+ unregisterObserver();
+
+ // The creator isn't interested in any further updates
+ if (isReset() || result == null) {
+ return;
+ }
+
+ mContact = result;
+
+ if (result.isLoaded()) {
+ mLookupUri = result.getLookupUri();
+
+ if (!result.isDirectoryEntry()) {
+ Log.i(TAG, "Registering content observer for " + mLookupUri);
+ if (mObserver == null) {
+ mObserver = new ForceLoadContentObserver();
+ }
+ getContext().getContentResolver().registerContentObserver(
+ mLookupUri, true, mObserver);
+ }
+
+ if (mPostViewNotification) {
+ // inform the source of the data that this contact is being looked at
+ postViewNotificationToSyncAdapter();
+ }
+ }
+
+ super.deliverResult(mContact);
+ }
+
+ /**
+ * Posts a message to the contributing sync adapters that have opted-in, notifying them
+ * that the contact has just been loaded
+ */
+ private void postViewNotificationToSyncAdapter() {
+ Context context = getContext();
+ for (RawContact rawContact : mContact.getRawContacts()) {
+ final long rawContactId = rawContact.getId();
+ if (mNotifiedRawContactIds.contains(rawContactId)) {
+ continue; // Already notified for this raw contact.
+ }
+ mNotifiedRawContactIds.add(rawContactId);
+ final AccountType accountType = rawContact.getAccountType(context);
+ final String serviceName = accountType.getViewContactNotifyServiceClassName();
+ final String servicePackageName = accountType.getViewContactNotifyServicePackageName();
+ if (!TextUtils.isEmpty(serviceName) && !TextUtils.isEmpty(servicePackageName)) {
+ final Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
+ final Intent intent = new Intent();
+ intent.setClassName(servicePackageName, serviceName);
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setDataAndType(uri, RawContacts.CONTENT_ITEM_TYPE);
+ try {
+ context.startService(intent);
+ } catch (Exception e) {
+ Log.e(TAG, "Error sending message to source-app", e);
+ }
+ }
+ }
+ }
+
+ private void unregisterObserver() {
+ if (mObserver != null) {
+ getContext().getContentResolver().unregisterContentObserver(mObserver);
+ mObserver = null;
+ }
+ }
+
+ /**
+ * Fully upgrades this ContactLoader to one with all lists fully loaded. When done, the
+ * new result will be delivered
+ */
+ public void upgradeToFullContact() {
+ // Everything requested already? Nothing to do, so let's bail out
+ if (mLoadGroupMetaData && mLoadInvitableAccountTypes
+ && mPostViewNotification && mComputeFormattedPhoneNumber) return;
+
+ mLoadGroupMetaData = true;
+ mLoadInvitableAccountTypes = true;
+ mPostViewNotification = true;
+ mComputeFormattedPhoneNumber = true;
+
+ // Cache the current result, so that we only load the "missing" parts of the contact.
+ cacheResult();
+
+ // Our load parameters have changed, so let's pretend the data has changed. Its the same
+ // thing, essentially.
+ onContentChanged();
+ }
+
+ public Uri getLookupUri() {
+ return mLookupUri;
+ }
+
+ @Override
+ protected void onStartLoading() {
+ if (mContact != null) {
+ deliverResult(mContact);
+ }
+
+ if (takeContentChanged() || mContact == null) {
+ forceLoad();
+ }
+ }
+
+ @Override
+ protected void onStopLoading() {
+ cancelLoad();
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+ cancelLoad();
+ unregisterObserver();
+ mContact = null;
+ }
+
+ /**
+ * Caches the result, which is useful when we switch from activity to activity, using the same
+ * contact. If the next load is for a different contact, the cached result will be dropped
+ */
+ public void cacheResult() {
+ if (mContact == null || !mContact.isLoaded()) {
+ sCachedResult = null;
+ } else {
+ sCachedResult = mContact;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/model/RawContact.java b/src/com/android/contacts/common/model/RawContact.java
new file mode 100644
index 0000000..3d8db85
--- /dev/null
+++ b/src/com/android/contacts/common/model/RawContact.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2012 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.common.model;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Entity;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.dataitem.DataItem;
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * RawContact represents a single raw contact in the raw contacts database.
+ * It has specialized getters/setters for raw contact
+ * items, and also contains a collection of DataItem objects. A RawContact contains the information
+ * from a single account.
+ *
+ * This allows RawContact objects to be thought of as a class with raw contact
+ * fields (like account type, name, data set, sync state, etc.) and a list of
+ * DataItem objects that represent contact information elements (like phone
+ * numbers, email, address, etc.).
+ */
+final public class RawContact implements Parcelable {
+
+ private AccountTypeManager mAccountTypeManager;
+ private final ContentValues mValues;
+ private final ArrayList<NamedDataItem> mDataItems;
+
+ final public static class NamedDataItem implements Parcelable {
+ public final Uri mUri;
+
+ // This use to be a DataItem. DataItem creation is now delayed until the point of request
+ // since there is no benefit to storing them here due to the multiple inheritance.
+ // Eventually instanceof still has to be used anyways to determine which sub-class of
+ // DataItem it is. And having parent DataItem's here makes it very difficult to serialize or
+ // parcelable.
+ //
+ // Instead of having a common DataItem super class, we should refactor this to be a generic
+ // Object where the object is a concrete class that no longer relies on ContentValues.
+ // (this will also make the classes easier to use).
+ // Since instanceof is used later anyways, having a list of Objects won't hurt and is no
+ // worse than having a DataItem.
+ public final ContentValues mContentValues;
+
+ public NamedDataItem(Uri uri, ContentValues values) {
+ this.mUri = uri;
+ this.mContentValues = values;
+ }
+
+ public NamedDataItem(Parcel parcel) {
+ this.mUri = parcel.readParcelable(Uri.class.getClassLoader());
+ this.mContentValues = parcel.readParcelable(ContentValues.class.getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeParcelable(mUri, i);
+ parcel.writeParcelable(mContentValues, i);
+ }
+
+ public static final Parcelable.Creator<NamedDataItem> CREATOR
+ = new Parcelable.Creator<NamedDataItem>() {
+
+ @Override
+ public NamedDataItem createFromParcel(Parcel parcel) {
+ return new NamedDataItem(parcel);
+ }
+
+ @Override
+ public NamedDataItem[] newArray(int i) {
+ return new NamedDataItem[i];
+ }
+ };
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(mUri, mContentValues);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+
+ final NamedDataItem other = (NamedDataItem) obj;
+ return Objects.equal(mUri, other.mUri) &&
+ Objects.equal(mContentValues, other.mContentValues);
+ }
+ }
+
+ public static RawContact createFrom(Entity entity) {
+ final ContentValues values = entity.getEntityValues();
+ final ArrayList<Entity.NamedContentValues> subValues = entity.getSubValues();
+
+ RawContact rawContact = new RawContact(values);
+ for (Entity.NamedContentValues subValue : subValues) {
+ rawContact.addNamedDataItemValues(subValue.uri, subValue.values);
+ }
+ return rawContact;
+ }
+
+ /**
+ * A RawContact object can be created with or without a context.
+ */
+ public RawContact() {
+ this(new ContentValues());
+ }
+
+ public RawContact(ContentValues values) {
+ mValues = values;
+ mDataItems = new ArrayList<NamedDataItem>();
+ }
+
+ /**
+ * Constructor for the parcelable.
+ *
+ * @param parcel The parcel to de-serialize from.
+ */
+ private RawContact(Parcel parcel) {
+ mValues = parcel.readParcelable(ContentValues.class.getClassLoader());
+ mDataItems = Lists.newArrayList();
+ parcel.readTypedList(mDataItems, NamedDataItem.CREATOR);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeParcelable(mValues, i);
+ parcel.writeTypedList(mDataItems);
+ }
+
+ /**
+ * Create for building the parcelable.
+ */
+ public static final Parcelable.Creator<RawContact> CREATOR
+ = new Parcelable.Creator<RawContact>() {
+
+ @Override
+ public RawContact createFromParcel(Parcel parcel) {
+ return new RawContact(parcel);
+ }
+
+ @Override
+ public RawContact[] newArray(int i) {
+ return new RawContact[i];
+ }
+ };
+
+ public AccountTypeManager getAccountTypeManager(Context context) {
+ if (mAccountTypeManager == null) {
+ mAccountTypeManager = AccountTypeManager.getInstance(context);
+ }
+ return mAccountTypeManager;
+ }
+
+ public ContentValues getValues() {
+ return mValues;
+ }
+
+ /**
+ * Returns the id of the raw contact.
+ */
+ public Long getId() {
+ return getValues().getAsLong(RawContacts._ID);
+ }
+
+ /**
+ * Returns the account name of the raw contact.
+ */
+ public String getAccountName() {
+ return getValues().getAsString(RawContacts.ACCOUNT_NAME);
+ }
+
+ /**
+ * Returns the account type of the raw contact.
+ */
+ public String getAccountTypeString() {
+ return getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ }
+
+ /**
+ * Returns the data set of the raw contact.
+ */
+ public String getDataSet() {
+ return getValues().getAsString(RawContacts.DATA_SET);
+ }
+
+ public boolean isDirty() {
+ return getValues().getAsBoolean(RawContacts.DIRTY);
+ }
+
+ public String getSourceId() {
+ return getValues().getAsString(RawContacts.SOURCE_ID);
+ }
+
+ public String getSync1() {
+ return getValues().getAsString(RawContacts.SYNC1);
+ }
+
+ public String getSync2() {
+ return getValues().getAsString(RawContacts.SYNC2);
+ }
+
+ public String getSync3() {
+ return getValues().getAsString(RawContacts.SYNC3);
+ }
+
+ public String getSync4() {
+ return getValues().getAsString(RawContacts.SYNC4);
+ }
+
+ public boolean isDeleted() {
+ return getValues().getAsBoolean(RawContacts.DELETED);
+ }
+
+ public long getContactId() {
+ return getValues().getAsLong(Contacts.Entity.CONTACT_ID);
+ }
+
+ public boolean isStarred() {
+ return getValues().getAsBoolean(Contacts.STARRED);
+ }
+
+ public AccountType getAccountType(Context context) {
+ return getAccountTypeManager(context).getAccountType(getAccountTypeString(), getDataSet());
+ }
+
+ /**
+ * Sets the account name, account type, and data set strings.
+ * Valid combinations for account-name, account-type, data-set
+ * 1) null, null, null (local account)
+ * 2) non-null, non-null, null (valid account without data-set)
+ * 3) non-null, non-null, non-null (valid account with data-set)
+ */
+ private void setAccount(String accountName, String accountType, String dataSet) {
+ final ContentValues values = getValues();
+ if (accountName == null) {
+ if (accountType == null && dataSet == null) {
+ // This is a local account
+ values.putNull(RawContacts.ACCOUNT_NAME);
+ values.putNull(RawContacts.ACCOUNT_TYPE);
+ values.putNull(RawContacts.DATA_SET);
+ return;
+ }
+ } else {
+ if (accountType != null) {
+ // This is a valid account, either with or without a dataSet.
+ values.put(RawContacts.ACCOUNT_NAME, accountName);
+ values.put(RawContacts.ACCOUNT_TYPE, accountType);
+ if (dataSet == null) {
+ values.putNull(RawContacts.DATA_SET);
+ } else {
+ values.put(RawContacts.DATA_SET, dataSet);
+ }
+ return;
+ }
+ }
+ throw new IllegalArgumentException(
+ "Not a valid combination of account name, type, and data set.");
+ }
+
+ public void setAccount(AccountWithDataSet accountWithDataSet) {
+ if (accountWithDataSet != null) {
+ setAccount(accountWithDataSet.name, accountWithDataSet.type,
+ accountWithDataSet.dataSet);
+ } else {
+ setAccount(null, null, null);
+ }
+ }
+
+ public void setAccountToLocal() {
+ setAccount(null, null, null);
+ }
+
+ /**
+ * Creates and inserts a DataItem object that wraps the content values, and returns it.
+ */
+ public void addDataItemValues(ContentValues values) {
+ addNamedDataItemValues(Data.CONTENT_URI, values);
+ }
+
+ public NamedDataItem addNamedDataItemValues(Uri uri, ContentValues values) {
+ final NamedDataItem namedItem = new NamedDataItem(uri, values);
+ mDataItems.add(namedItem);
+ return namedItem;
+ }
+
+ public ArrayList<ContentValues> getContentValues() {
+ final ArrayList<ContentValues> list = Lists.newArrayListWithCapacity(mDataItems.size());
+ for (NamedDataItem dataItem : mDataItems) {
+ if (Data.CONTENT_URI.equals(dataItem.mUri)) {
+ list.add(dataItem.mContentValues);
+ }
+ }
+ return list;
+ }
+
+ public List<DataItem> getDataItems() {
+ final ArrayList<DataItem> list = Lists.newArrayListWithCapacity(mDataItems.size());
+ for (NamedDataItem dataItem : mDataItems) {
+ if (Data.CONTENT_URI.equals(dataItem.mUri)) {
+ list.add(DataItem.createFrom(dataItem.mContentValues));
+ }
+ }
+ return list;
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("RawContact: ").append(mValues);
+ for (RawContact.NamedDataItem namedDataItem : mDataItems) {
+ sb.append("\n ").append(namedDataItem.mUri);
+ sb.append("\n -> ").append(namedDataItem.mContentValues);
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(mValues, mDataItems);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+
+ RawContact other = (RawContact) obj;
+ return Objects.equal(mValues, other.mValues) &&
+ Objects.equal(mDataItems, other.mDataItems);
+ }
+}
diff --git a/src/com/android/contacts/common/model/RawContactDelta.java b/src/com/android/contacts/common/model/RawContactDelta.java
new file mode 100644
index 0000000..b8709c3
--- /dev/null
+++ b/src/com/android/contacts/common/model/RawContactDelta.java
@@ -0,0 +1,660 @@
+/*
+ * 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.common.model;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderOperation.Builder;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.BaseColumns;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Profile;
+import android.provider.ContactsContract.RawContacts;
+import android.util.Log;
+
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.BuilderWrapper;
+import com.android.contacts.common.model.CPOWrapper;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.testing.NeededForTesting;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Contains a {@link RawContact} and records any modifications separately so the
+ * original {@link RawContact} 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 RawContact}, which then becomes an insert {@link RawContacts} case.
+ * <p>
+ * When applying modifications over an {@link RawContact}, we try finding the
+ * original {@link Data#_ID} rows where the modifications took place. If those
+ * rows are missing from the new {@link RawContact}, we know the original data must
+ * be deleted, but to preserve the user modifications we treat as an insert.
+ */
+public class RawContactDelta 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 = false;
+
+ /**
+ * Direct values from {@link Entity#getEntityValues()}.
+ */
+ private ValuesDelta mValues;
+
+ /**
+ * URI used for contacts queries, by default it is set to query raw contacts.
+ * It can be set to query the profile's raw contact(s).
+ */
+ private Uri mContactsQueryUri = RawContacts.CONTENT_URI;
+
+ /**
+ * Internal map of children values from {@link Entity#getSubValues()}, which
+ * we store here sorted into {@link Data#MIMETYPE} bins.
+ */
+ private final HashMap<String, ArrayList<ValuesDelta>> mEntries = Maps.newHashMap();
+
+ public RawContactDelta() {
+ }
+
+ public RawContactDelta(ValuesDelta values) {
+ mValues = values;
+ }
+
+ /**
+ * Build an {@link RawContactDelta} using the given {@link RawContact} as a
+ * starting point; the "before" snapshot.
+ */
+ public static RawContactDelta fromBefore(RawContact before) {
+ final RawContactDelta rawContactDelta = new RawContactDelta();
+ rawContactDelta.mValues = ValuesDelta.fromBefore(before.getValues());
+ rawContactDelta.mValues.setIdColumn(RawContacts._ID);
+ for (final ContentValues values : before.getContentValues()) {
+ rawContactDelta.addEntry(ValuesDelta.fromBefore(values));
+ }
+ return rawContactDelta;
+ }
+
+ /**
+ * Merge the "after" values from the given {@link RawContactDelta} onto the
+ * "before" state represented by this {@link RawContactDelta}, discarding any
+ * existing "after" states. This is typically used when re-parenting changes
+ * onto an updated {@link Entity}.
+ */
+ public static RawContactDelta mergeAfter(RawContactDelta local, RawContactDelta 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 RawContactDelta();
+
+ 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
+ */
+ @NeededForTesting
+ 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 AccountType that this raw-contact belongs to.
+ */
+ public AccountType getRawContactAccountType(Context context) {
+ ContentValues entityValues = getValues().getCompleteValues();
+ String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
+ String dataSet = entityValues.getAsString(RawContacts.DATA_SET);
+ return AccountTypeManager.getInstance(context).getAccountType(type, dataSet);
+ }
+
+ public Long getRawContactId() {
+ return getValues().getAsLong(RawContacts._ID);
+ }
+
+ public String getAccountName() {
+ return getValues().getAsString(RawContacts.ACCOUNT_NAME);
+ }
+
+ public String getAccountType() {
+ return getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ }
+
+ public String getDataSet() {
+ return getValues().getAsString(RawContacts.DATA_SET);
+ }
+
+ public AccountType getAccountType(AccountTypeManager manager) {
+ return manager.getAccountType(getAccountType(), getDataSet());
+ }
+
+ public boolean isVisible() {
+ return getValues().isVisible();
+ }
+
+ /**
+ * 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;
+ }
+
+ public ArrayList<ContentValues> getContentValues() {
+ ArrayList<ContentValues> values = Lists.newArrayList();
+ for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
+ for (ValuesDelta entry : mimeEntries) {
+ if (!entry.isDelete()) {
+ values.add(entry.getCompleteValues());
+ }
+ }
+ }
+ return values;
+ }
+
+ /**
+ * 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 RawContactDelta) {
+ final RawContactDelta other = (RawContactDelta)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("Uri=");
+ builder.append(mContactsQueryUri);
+ builder.append(", Values=");
+ builder.append(mValues != null ? mValues.toString() : "null");
+ builder.append(", Entries={");
+ 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());
+ }
+ }
+
+ /**
+ * For compatibility purpose, this method is copied from {@link #possibleAdd} and takes
+ * BuilderWrapper and an ArrayList of CPOWrapper as parameters.
+ */
+ private void possibleAddWrapper(ArrayList<CPOWrapper> diff, BuilderWrapper bw) {
+ if (bw != null && bw.getBuilder() != null) {
+ diff.add(new CPOWrapper(bw.getBuilder().build(), bw.getType()));
+ }
+ }
+
+ /**
+ * 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 Builder builder = buildAssertHelper();
+ if (builder != null) {
+ buildInto.add(builder.build());
+ }
+ }
+
+ /**
+ * For compatibility purpose, this method is copied from {@link #buildAssert} and takes an
+ * ArrayList of CPOWrapper as parameter.
+ */
+ public void buildAssertWrapper(ArrayList<CPOWrapper> buildInto) {
+ final Builder builder = buildAssertHelper();
+ if (builder != null) {
+ buildInto.add(new CPOWrapper(builder.build(), CompatUtils.TYPE_ASSERT));
+ }
+ }
+
+ private Builder buildAssertHelper() {
+ final boolean isContactInsert = mValues.isInsert();
+ ContentProviderOperation.Builder builder = null;
+ 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 builder;
+ builder = ContentProviderOperation.newAssertQuery(mContactsQueryUri);
+ builder.withSelection(RawContacts._ID + "=" + beforeId, null);
+ builder.withValue(RawContacts.VERSION, beforeVersion);
+ }
+ return builder;
+ }
+
+ /**
+ * Build a list of {@link ContentProviderOperation} that will transform the
+ * current "before" {@link Entity} state into the modified state which this
+ * {@link RawContactDelta} 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;
+
+ if (isContactInsert) {
+ // TODO: for now simply disabling aggregation when a new contact is
+ // created on the phone. In the future, will show aggregation suggestions
+ // after saving the contact.
+ mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
+ }
+
+ // Build possible operation at Contact level
+ builder = mValues.buildDiff(mContactsQueryUri);
+ 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;
+
+ // Use the profile data URI if the contact is the profile.
+ if (mContactsQueryUri.equals(Profile.CONTENT_RAW_CONTACTS_URI)) {
+ builder = child.buildDiff(Uri.withAppendedPath(Profile.CONTENT_URI,
+ RawContacts.Data.CONTENT_DIRECTORY));
+ } else {
+ 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 mode as last operation
+ builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_DEFAULT);
+ buildInto.add(builder.build());
+ } else if (isContactInsert) {
+ // Restore aggregation mode as last operation
+ builder = ContentProviderOperation.newUpdate(mContactsQueryUri);
+ builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT);
+ builder.withSelection(RawContacts._ID + "=?", new String[1]);
+ builder.withSelectionBackReference(0, firstIndex);
+ buildInto.add(builder.build());
+ }
+ }
+
+ /**
+ * For compatibility purpose, this method is copied from {@link #buildDiff} and takes an
+ * ArrayList of CPOWrapper as parameter.
+ */
+ public void buildDiffWrapper(ArrayList<CPOWrapper> 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();
+
+ if (isContactInsert) {
+ // TODO: for now simply disabling aggregation when a new contact is
+ // created on the phone. In the future, will show aggregation suggestions
+ // after saving the contact.
+ mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
+ }
+
+ // Build possible operation at Contact level
+ BuilderWrapper bw = mValues.buildDiffWrapper(mContactsQueryUri);
+ possibleAddWrapper(buildInto, bw);
+
+ // Build operations for all children
+ for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
+ for (ValuesDelta child : mimeEntries) {
+ // Ignore children if parent was deleted
+ if (isContactDelete) continue;
+
+ // Use the profile data URI if the contact is the profile.
+ if (mContactsQueryUri.equals(Profile.CONTENT_RAW_CONTACTS_URI)) {
+ bw = child.buildDiffWrapper(Uri.withAppendedPath(Profile.CONTENT_URI,
+ RawContacts.Data.CONTENT_DIRECTORY));
+ } else {
+ bw = child.buildDiffWrapper(Data.CONTENT_URI);
+ }
+
+ if (child.isInsert()) {
+ if (isContactInsert) {
+ // Parent is brand new insert, so back-reference _id
+ bw.getBuilder().withValueBackReference(Data.RAW_CONTACT_ID, firstIndex);
+ } else {
+ // Inserting under existing, so fill with known _id
+ bw.getBuilder().withValue(Data.RAW_CONTACT_ID, beforeId);
+ }
+ } else if (isContactInsert && bw != null && bw.getBuilder() != null) {
+ // Child must be insert when Contact insert
+ throw new IllegalArgumentException("When parent insert, child must be also");
+ }
+ possibleAddWrapper(buildInto, bw);
+ }
+ }
+
+ final boolean addedOperations = buildInto.size() > firstIndex;
+ if (addedOperations && isContactUpdate) {
+ // Suspend aggregation while persisting updates
+ Builder builder =
+ buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_SUSPENDED);
+ buildInto.add(firstIndex, new CPOWrapper(builder.build(), CompatUtils.TYPE_UPDATE));
+
+ // Restore aggregation mode as last operation
+ builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_DEFAULT);
+ buildInto.add(new CPOWrapper(builder.build(), CompatUtils.TYPE_UPDATE));
+ } else if (isContactInsert) {
+ // Restore aggregation mode as last operation
+ Builder builder = ContentProviderOperation.newUpdate(mContactsQueryUri);
+ builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT);
+ builder.withSelection(RawContacts._ID + "=?", new String[1]);
+ builder.withSelectionBackReference(0, firstIndex);
+ buildInto.add(new CPOWrapper(builder.build(), CompatUtils.TYPE_UPDATE));
+ }
+ }
+
+ /**
+ * 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(mContactsQueryUri);
+ 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);
+ dest.writeParcelable(mContactsQueryUri, flags);
+ for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
+ for (ValuesDelta child : mimeEntries) {
+ dest.writeParcelable(child, flags);
+ }
+ }
+ }
+
+ public void readFromParcel(Parcel source) {
+ final ClassLoader loader = getClass().getClassLoader();
+ final int size = source.readInt();
+ mValues = source.<ValuesDelta> readParcelable(loader);
+ mContactsQueryUri = source.<Uri> readParcelable(loader);
+ for (int i = 0; i < size; i++) {
+ final ValuesDelta child = source.<ValuesDelta> readParcelable(loader);
+ this.addEntry(child);
+ }
+ }
+
+ /**
+ * Used to set the query URI to the profile URI to store profiles.
+ */
+ public void setProfileQueryUri() {
+ mContactsQueryUri = Profile.CONTENT_RAW_CONTACTS_URI;
+ }
+
+ public static final Parcelable.Creator<RawContactDelta> CREATOR =
+ new Parcelable.Creator<RawContactDelta>() {
+ public RawContactDelta createFromParcel(Parcel in) {
+ final RawContactDelta state = new RawContactDelta();
+ state.readFromParcel(in);
+ return state;
+ }
+
+ public RawContactDelta[] newArray(int size) {
+ return new RawContactDelta[size];
+ }
+ };
+
+}
diff --git a/src/com/android/contacts/common/model/RawContactDeltaList.java b/src/com/android/contacts/common/model/RawContactDeltaList.java
new file mode 100644
index 0000000..6964643
--- /dev/null
+++ b/src/com/android/contacts/common/model/RawContactDeltaList.java
@@ -0,0 +1,573 @@
+/*
+ * 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.common.model;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderOperation.Builder;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Entity;
+import android.content.EntityIterator;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.ContactsContract.AggregationExceptions;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.util.Log;
+
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.model.CPOWrapper;
+import com.android.contacts.common.model.ValuesDelta;
+
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+
+/**
+ * Container for multiple {@link RawContactDelta} objects, usually when editing
+ * together as an entire aggregate. Provides convenience methods for parceling
+ * and applying another {@link RawContactDeltaList} over it.
+ */
+public class RawContactDeltaList extends ArrayList<RawContactDelta> implements Parcelable {
+ private static final String TAG = RawContactDeltaList.class.getSimpleName();
+ private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
+
+ private boolean mSplitRawContacts;
+ private long[] mJoinWithRawContactIds;
+
+ public RawContactDeltaList() {
+ }
+
+ /**
+ * Create an {@link RawContactDeltaList} 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 RawContactDeltaList fromQuery(Uri entityUri, ContentResolver resolver,
+ String selection, String[] selectionArgs, String sortOrder) {
+ final EntityIterator iterator = RawContacts.newEntityIterator(
+ resolver.query(entityUri, null, selection, selectionArgs, sortOrder));
+ try {
+ return fromIterator(iterator);
+ } finally {
+ iterator.close();
+ }
+ }
+
+ /**
+ * Create an {@link RawContactDeltaList} that contains the entities of the Iterator as before
+ * values. This function can be passed an iterator of Entity objects or an iterator of
+ * RawContact objects.
+ */
+ public static RawContactDeltaList fromIterator(Iterator<?> iterator) {
+ final RawContactDeltaList state = new RawContactDeltaList();
+ state.addAll(iterator);
+ return state;
+ }
+
+ public void addAll(Iterator<?> iterator) {
+ // Perform background query to pull contact details
+ while (iterator.hasNext()) {
+ // Read all contacts into local deltas to prepare for edits
+ Object nextObject = iterator.next();
+ final RawContact before = nextObject instanceof Entity
+ ? RawContact.createFrom((Entity) nextObject)
+ : (RawContact) nextObject;
+ final RawContactDelta rawContactDelta = RawContactDelta.fromBefore(before);
+ add(rawContactDelta);
+ }
+ }
+
+ /**
+ * Merge the "after" values from the given {@link RawContactDeltaList}, discarding any
+ * previous "after" states. This is typically used when re-parenting user
+ * edits onto an updated {@link RawContactDeltaList}.
+ */
+ public static RawContactDeltaList mergeAfter(RawContactDeltaList local,
+ RawContactDeltaList remote) {
+ if (local == null) local = new RawContactDeltaList();
+
+ // For each entity in the remote set, try matching over existing
+ for (RawContactDelta remoteEntity : remote) {
+ final Long rawContactId = remoteEntity.getValues().getId();
+
+ // Find or create local match and merge
+ final RawContactDelta localEntity = local.getByRawContactId(rawContactId);
+ final RawContactDelta merged = RawContactDelta.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 RawContactDelta} objects represent. This method specifically creates
+ * any {@link AggregationExceptions} rules needed to groups edits together.
+ */
+ public ArrayList<ContentProviderOperation> buildDiff() {
+ if (VERBOSE_LOGGING) {
+ Log.v(TAG, "buildDiff: list=" + toString());
+ }
+ final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+
+ final long rawContactId = this.findRawContactId();
+ int firstInsertRow = -1;
+
+ // First pass enforces versions remain consistent
+ for (RawContactDelta delta : this) {
+ delta.buildAssert(diff);
+ }
+
+ final int assertMark = diff.size();
+ int backRefs[] = new int[size()];
+
+ int rawContactIndex = 0;
+
+ // Second pass builds actual operations
+ for (RawContactDelta delta : this) {
+ final int firstBatch = diff.size();
+ final boolean isInsert = delta.isContactInsert();
+ backRefs[rawContactIndex++] = isInsert ? firstBatch : -1;
+
+ delta.buildDiff(diff);
+
+ // If the user chose to join with some other existing raw contact(s) at save time,
+ // add aggregation exceptions for all those raw contacts.
+ if (mJoinWithRawContactIds != null) {
+ for (Long joinedRawContactId : mJoinWithRawContactIds) {
+ final Builder builder = beginKeepTogether();
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, joinedRawContactId);
+ if (rawContactId != -1) {
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId);
+ } else {
+ builder.withValueBackReference(
+ AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
+ }
+ diff.add(builder.build());
+ }
+ }
+
+ // Only create rules for inserts
+ if (!isInsert) 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();
+ }
+ if (VERBOSE_LOGGING) {
+ Log.v(TAG, "buildDiff: ops=" + diffToString(diff));
+ }
+ return diff;
+ }
+
+ /**
+ * For compatibility purpose, this method is copied from {@link #buildDiff} and returns an
+ * ArrayList of CPOWrapper.
+ */
+ public ArrayList<CPOWrapper> buildDiffWrapper() {
+ if (VERBOSE_LOGGING) {
+ Log.v(TAG, "buildDiffWrapper: list=" + toString());
+ }
+ final ArrayList<CPOWrapper> diffWrapper = Lists.newArrayList();
+
+ final long rawContactId = this.findRawContactId();
+ int firstInsertRow = -1;
+
+ // First pass enforces versions remain consistent
+ for (RawContactDelta delta : this) {
+ delta.buildAssertWrapper(diffWrapper);
+ }
+
+ final int assertMark = diffWrapper.size();
+ int backRefs[] = new int[size()];
+
+ int rawContactIndex = 0;
+
+ // Second pass builds actual operations
+ for (RawContactDelta delta : this) {
+ final int firstBatch = diffWrapper.size();
+ final boolean isInsert = delta.isContactInsert();
+ backRefs[rawContactIndex++] = isInsert ? firstBatch : -1;
+
+ delta.buildDiffWrapper(diffWrapper);
+
+ // If the user chose to join with some other existing raw contact(s) at save time,
+ // add aggregation exceptions for all those raw contacts.
+ if (mJoinWithRawContactIds != null) {
+ for (Long joinedRawContactId : mJoinWithRawContactIds) {
+ final Builder builder = beginKeepTogether();
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, joinedRawContactId);
+ if (rawContactId != -1) {
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId);
+ } else {
+ builder.withValueBackReference(
+ AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
+ }
+ diffWrapper.add(new CPOWrapper(builder.build(), CompatUtils.TYPE_UPDATE));
+ }
+ }
+
+ // Only create rules for inserts
+ if (!isInsert) 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);
+ diffWrapper.add(new CPOWrapper(builder.build(), CompatUtils.TYPE_UPDATE));
+
+ } 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);
+ diffWrapper.add(new CPOWrapper(builder.build(), CompatUtils.TYPE_UPDATE));
+ }
+ }
+
+ if (mSplitRawContacts) {
+ buildSplitContactDiffWrapper(diffWrapper, backRefs);
+ }
+
+ // No real changes if only left with asserts
+ if (diffWrapper.size() == assertMark) {
+ diffWrapper.clear();
+ }
+ if (VERBOSE_LOGGING) {
+ Log.v(TAG, "buildDiff: ops=" + diffToStringWrapper(diffWrapper));
+ }
+ return diffWrapper;
+ }
+
+ private static String diffToString(ArrayList<ContentProviderOperation> ops) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("[\n");
+ for (ContentProviderOperation op : ops) {
+ sb.append(op.toString());
+ sb.append(",\n");
+ }
+ sb.append("]\n");
+ return sb.toString();
+ }
+
+ /**
+ * For compatibility purpose.
+ */
+ private static String diffToStringWrapper(ArrayList<CPOWrapper> cpoWrappers) {
+ ArrayList<ContentProviderOperation> ops = Lists.newArrayList();
+ for (CPOWrapper cpoWrapper : cpoWrappers) {
+ ops.add(cpoWrapper.getOperation());
+ }
+ return diffToString(ops);
+ }
+
+ /**
+ * 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) {
+ final int count = size();
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < count; j++) {
+ if (i == j) {
+ continue;
+ }
+ final Builder builder = buildSplitContactDiffHelper(i, j, backRefs);
+ if (builder != null) {
+ diff.add(builder.build());
+ }
+ }
+ }
+ }
+
+ /**
+ * For compatibility purpose, this method is copied from {@link #buildSplitContactDiff} and
+ * takes an ArrayList of CPOWrapper as parameter.
+ */
+ private void buildSplitContactDiffWrapper(final ArrayList<CPOWrapper> diff, int[] backRefs) {
+ final int count = size();
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < count; j++) {
+ if (i == j) {
+ continue;
+ }
+ final Builder builder = buildSplitContactDiffHelper(i, j, backRefs);
+ if (builder != null) {
+ diff.add(new CPOWrapper(builder.build(), CompatUtils.TYPE_UPDATE));
+ }
+ }
+ }
+ }
+
+ private Builder buildSplitContactDiffHelper(int index1, int index2, int[] backRefs) {
+ final Builder builder =
+ ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI);
+ builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_SEPARATE);
+
+ Long rawContactId1 = get(index1).getValues().getAsLong(RawContacts._ID);
+ int backRef1 = backRefs[index1];
+ if (rawContactId1 != null && rawContactId1 >= 0) {
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
+ } else if (backRef1 >= 0) {
+ builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, backRef1);
+ } else {
+ return null;
+ }
+
+ Long rawContactId2 = get(index2).getValues().getAsLong(RawContacts._ID);
+ int backRef2 = backRefs[index2];
+ if (rawContactId2 != null && rawContactId2 >= 0) {
+ builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
+ } else if (backRef2 >= 0) {
+ builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, backRef2);
+ } else {
+ return null;
+ }
+ return builder;
+ }
+
+ /**
+ * Search all contained {@link RawContactDelta} for the first one with an
+ * existing {@link RawContacts#_ID} value. Usually used when creating
+ * {@link AggregationExceptions} during an update.
+ */
+ public long findRawContactId() {
+ for (RawContactDelta 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 RawContactDelta}.
+ */
+ public Long getRawContactId(int index) {
+ if (index >= 0 && index < this.size()) {
+ final RawContactDelta delta = this.get(index);
+ final ValuesDelta values = delta.getValues();
+ if (values.isVisible()) {
+ return values.getAsLong(RawContacts._ID);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Find the raw-contact (an {@link RawContactDelta}) with the specified ID.
+ */
+ public RawContactDelta 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;
+ }
+
+ /**
+ * Return the index of the first RawContactDelta corresponding to a writable raw-contact, or -1.
+ * */
+ public int indexOfFirstWritableRawContact(Context context) {
+ // Find the first writable entity.
+ int entityIndex = 0;
+ for (RawContactDelta delta : this) {
+ if (delta.getRawContactAccountType(context).areContactsWritable()) return entityIndex;
+ entityIndex++;
+ }
+ return -1;
+ }
+
+ /** Return the first RawContactDelta corresponding to a writable raw-contact, or null. */
+ public RawContactDelta getFirstWritableRawContact(Context context) {
+ final int index = indexOfFirstWritableRawContact(context);
+ return (index == -1) ? null : get(index);
+ }
+
+ public ValuesDelta getSuperPrimaryEntry(final String mimeType) {
+ ValuesDelta primary = null;
+ ValuesDelta randomEntry = null;
+ for (RawContactDelta 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;
+ }
+
+ /**
+ * Sets a flag that will split ("explode") the raw_contacts into seperate contacts
+ */
+ public void markRawContactsForSplitting() {
+ mSplitRawContacts = true;
+ }
+
+ public boolean isMarkedForSplitting() {
+ return mSplitRawContacts;
+ }
+
+ public void setJoinWithRawContacts(long[] rawContactIds) {
+ mJoinWithRawContactIds = rawContactIds;
+ }
+
+ public boolean isMarkedForJoining() {
+ return mJoinWithRawContactIds != null && mJoinWithRawContactIds.length > 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int describeContents() {
+ // Nothing special about this parcel
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ final int size = this.size();
+ dest.writeInt(size);
+ for (RawContactDelta delta : this) {
+ dest.writeParcelable(delta, flags);
+ }
+ dest.writeLongArray(mJoinWithRawContactIds);
+ dest.writeInt(mSplitRawContacts ? 1 : 0);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void readFromParcel(Parcel source) {
+ final ClassLoader loader = getClass().getClassLoader();
+ final int size = source.readInt();
+ for (int i = 0; i < size; i++) {
+ this.add(source.<RawContactDelta> readParcelable(loader));
+ }
+ mJoinWithRawContactIds = source.createLongArray();
+ mSplitRawContacts = source.readInt() != 0;
+ }
+
+ public static final Parcelable.Creator<RawContactDeltaList> CREATOR =
+ new Parcelable.Creator<RawContactDeltaList>() {
+ @Override
+ public RawContactDeltaList createFromParcel(Parcel in) {
+ final RawContactDeltaList state = new RawContactDeltaList();
+ state.readFromParcel(in);
+ return state;
+ }
+
+ @Override
+ public RawContactDeltaList[] newArray(int size) {
+ return new RawContactDeltaList[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("(");
+ sb.append("Split=");
+ sb.append(mSplitRawContacts);
+ sb.append(", Join=[");
+ sb.append(Arrays.toString(mJoinWithRawContactIds));
+ sb.append("], Values=");
+ sb.append(super.toString());
+ sb.append(")");
+ return sb.toString();
+ }
+}
diff --git a/src/com/android/contacts/common/model/RawContactModifier.java b/src/com/android/contacts/common/model/RawContactModifier.java
new file mode 100644
index 0000000..fd028e3
--- /dev/null
+++ b/src/com/android/contacts/common/model/RawContactModifier.java
@@ -0,0 +1,1424 @@
+/*
+ * 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.common.model;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+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.Relation;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.Intents.Insert;
+import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.util.CommonDateUtils;
+import com.android.contacts.common.util.DateUtils;
+import com.android.contacts.common.util.NameConverter;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountType.EditField;
+import com.android.contacts.common.model.account.AccountType.EditType;
+import com.android.contacts.common.model.account.AccountType.EventEditType;
+import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.model.dataitem.PhoneDataItem;
+import com.android.contacts.common.model.dataitem.StructuredNameDataItem;
+
+import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ * Helper methods for modifying an {@link RawContactDelta}, such as inserting
+ * new rows, or enforcing {@link AccountType}.
+ */
+public class RawContactModifier {
+ private static final String TAG = RawContactModifier.class.getSimpleName();
+
+ /** Set to true in order to view logs on entity operations */
+ private static final boolean DEBUG = false;
+
+ /**
+ * For the given {@link RawContactDelta}, determine if the given
+ * {@link DataKind} could be inserted under specific
+ * {@link AccountType}.
+ */
+ public static boolean canInsert(RawContactDelta 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(RawContactDelta state, DataKind kind) {
+ if (RawContactModifier.hasEditTypes(kind)) {
+ return (getValidTypes(state, kind, null, true, null, true).size() > 0);
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Ensure that at least one of the given {@link DataKind} exists in the
+ * given {@link RawContactDelta} state, and try creating one if none exist.
+ * @return The child (either newly created or the first existing one), or null if the
+ * account doesn't support this {@link DataKind}.
+ */
+ public static ValuesDelta ensureKindExists(
+ RawContactDelta state, AccountType accountType, String mimeType) {
+ final DataKind kind = accountType.getKindForMimetype(mimeType);
+ final boolean hasChild = state.getMimeEntriesCount(mimeType, true) > 0;
+
+ if (kind != null) {
+ if (hasChild) {
+ // Return the first entry.
+ return state.getMimeEntries(mimeType).get(0);
+ } else {
+ // 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);
+ }
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * For the given {@link RawContactDelta} and {@link DataKind}, return the
+ * list possible {@link EditType} options available based on
+ * {@link AccountType}.
+ *
+ * @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(RawContactDelta, DataKind)}.
+ * @param checkOverall If true, check if the overall number of types is under limit.
+ */
+ public static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind,
+ EditType forceInclude, boolean includeSecondary, SparseIntArray typeCount,
+ boolean checkOverall) {
+ final ArrayList<EditType> validTypes = new ArrayList<EditType>();
+
+ // 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
+ boolean validOverall = true;
+ if (checkOverall) {
+ final int overallCount = typeCount.get(FREQUENCY_TOTAL);
+ validOverall = (kind.typeOverallMax == -1 ? true
+ : overallCount < kind.typeOverallMax);
+ }
+
+ for (EditType type : kind.typeList) {
+ 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 RawContactDelta}. 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(RawContactDelta 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(RawContactDelta state, DataKind kind,
+ boolean includeSecondary, int exactValue) {
+ // Shortcut when no types
+ if (kind == null || 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, /*checkOverall=*/ true);
+ 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 RawContactDelta}. Tries using the best {@link EditType} found using
+ * {@link #getBestValidType(RawContactDelta, DataKind, boolean, int)}.
+ */
+ public static ValuesDelta insertChild(RawContactDelta state, DataKind kind) {
+ // Bail early if invalid kind
+ if (kind == null) return null;
+ // 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 RawContactDelta}, marked with the given {@link EditType}.
+ */
+ public static ValuesDelta insertChild(RawContactDelta 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 RawContactDelta}
+ * from the given {@link RawContactDeltaList}, assuming the given {@link AccountTypeManager}
+ * dictates the structure for various fields. This method ignores rows not
+ * described by the {@link AccountType}.
+ */
+ public static void trimEmpty(RawContactDeltaList set, AccountTypeManager accountTypes) {
+ for (RawContactDelta state : set) {
+ ValuesDelta values = state.getValues();
+ final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
+ final String dataSet = values.getAsString(RawContacts.DATA_SET);
+ final AccountType type = accountTypes.getAccountType(accountType, dataSet);
+ trimEmpty(state, type);
+ }
+ }
+
+ public static boolean hasChanges(RawContactDeltaList set, AccountTypeManager accountTypes) {
+ return hasChanges(set, accountTypes, /* excludedMimeTypes =*/ null);
+ }
+
+ public static boolean hasChanges(RawContactDeltaList set, AccountTypeManager accountTypes,
+ Set<String> excludedMimeTypes) {
+ if (set.isMarkedForSplitting() || set.isMarkedForJoining()) {
+ return true;
+ }
+
+ for (RawContactDelta state : set) {
+ ValuesDelta values = state.getValues();
+ final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
+ final String dataSet = values.getAsString(RawContacts.DATA_SET);
+ final AccountType type = accountTypes.getAccountType(accountType, dataSet);
+ if (hasChanges(state, type, excludedMimeTypes)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Processing to trim any empty {@link ValuesDelta} rows from the given
+ * {@link RawContactDelta}, assuming the given {@link AccountType} dictates
+ * the structure for various fields. This method ignores rows not described
+ * by the {@link AccountType}.
+ */
+ public static void trimEmpty(RawContactDelta state, AccountType accountType) {
+ boolean hasValues = false;
+
+ // Walk through entries for each well-known kind
+ for (DataKind kind : accountType.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 isGoogleAccount = TextUtils.equals(GoogleAccountType.ACCOUNT_TYPE,
+ state.getValues().getAsString(RawContacts.ACCOUNT_TYPE));
+ final boolean isPhoto = TextUtils.equals(Photo.CONTENT_ITEM_TYPE, kind.mimeType);
+ final boolean isGooglePhoto = isPhoto && isGoogleAccount;
+
+ if (RawContactModifier.isEmpty(entry, kind) && !isGooglePhoto) {
+ if (DEBUG) {
+ Log.v(TAG, "Trimming: " + entry.toString());
+ }
+ entry.markDeleted();
+ } else if (!entry.isFromTemplate()) {
+ hasValues = true;
+ }
+ }
+ }
+ if (!hasValues) {
+ // Trim overall entity if no children exist
+ state.markDeleted();
+ }
+ }
+
+ private static boolean hasChanges(RawContactDelta state, AccountType accountType,
+ Set<String> excludedMimeTypes) {
+ for (DataKind kind : accountType.getSortedDataKinds()) {
+ final String mimeType = kind.mimeType;
+ if (excludedMimeTypes != null && excludedMimeTypes.contains(mimeType)) continue;
+ final ArrayList<ValuesDelta> entries = state.getMimeEntries(mimeType);
+ if (entries == null) continue;
+
+ for (ValuesDelta entry : entries) {
+ // An empty Insert must be ignored, because it won't save anything (an example
+ // is an empty name that stays empty)
+ final boolean isRealInsert = entry.isInsert() && !isEmpty(entry, kind);
+ if (isRealInsert || entry.isUpdate() || entry.isDelete()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Test if the given {@link ValuesDelta} would be considered "empty" in
+ * terms of {@link DataKind#fieldList}.
+ */
+ public static boolean isEmpty(ValuesDelta values, DataKind kind) {
+ if (Photo.CONTENT_ITEM_TYPE.equals(kind.mimeType)) {
+ return values.isInsert() && values.getAsByteArray(Photo.PHOTO) == null;
+ }
+
+ // No defined fields mean this row is always empty
+ if (kind.fieldList == null) return true;
+
+ 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)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Compares corresponding fields in values1 and values2. Only the fields
+ * declared by the DataKind are taken into consideration.
+ */
+ protected static boolean areEqual(ValuesDelta values1, ContentValues values2, DataKind kind) {
+ if (kind.fieldList == null) return false;
+
+ for (EditField field : kind.fieldList) {
+ final String value1 = values1.getAsString(field.column);
+ final String value2 = values2.getAsString(field.column);
+ if (!TextUtils.equals(value1, value2)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Parse the given {@link Bundle} into the given {@link RawContactDelta} state,
+ * assuming the extras defined through {@link Intents}.
+ */
+ public static void parseExtras(Context context, AccountType accountType, RawContactDelta state,
+ Bundle extras) {
+ if (extras == null || extras.size() == 0) {
+ // Bail early if no useful data
+ return;
+ }
+
+ parseStructuredNameExtra(context, accountType, state, extras);
+ parseStructuredPostalExtra(accountType, state, extras);
+
+ {
+ // Phone
+ final DataKind kind = accountType.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 = accountType.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 = accountType.getKindForMimetype(Im.CONTENT_ITEM_TYPE);
+ fixupLegacyImType(extras);
+ parseExtras(state, kind, extras, Insert.IM_PROTOCOL, Insert.IM_HANDLE, Im.DATA);
+ }
+
+ // Organization
+ final boolean hasOrg = extras.containsKey(Insert.COMPANY)
+ || extras.containsKey(Insert.JOB_TITLE);
+ final DataKind kindOrg = accountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
+ if (hasOrg && RawContactModifier.canInsert(state, kindOrg)) {
+ final ValuesDelta child = RawContactModifier.insertChild(state, kindOrg);
+
+ final String company = extras.getString(Insert.COMPANY);
+ if (ContactsUtils.isGraphic(company)) {
+ child.put(Organization.COMPANY, company);
+ }
+
+ final String title = extras.getString(Insert.JOB_TITLE);
+ if (ContactsUtils.isGraphic(title)) {
+ child.put(Organization.TITLE, title);
+ }
+ }
+
+ // Notes
+ final boolean hasNotes = extras.containsKey(Insert.NOTES);
+ final DataKind kindNotes = accountType.getKindForMimetype(Note.CONTENT_ITEM_TYPE);
+ if (hasNotes && RawContactModifier.canInsert(state, kindNotes)) {
+ final ValuesDelta child = RawContactModifier.insertChild(state, kindNotes);
+
+ final String notes = extras.getString(Insert.NOTES);
+ if (ContactsUtils.isGraphic(notes)) {
+ child.put(Note.NOTE, notes);
+ }
+ }
+
+ // Arbitrary additional data
+ ArrayList<ContentValues> values = extras.getParcelableArrayList(Insert.DATA);
+ if (values != null) {
+ parseValues(state, accountType, values);
+ }
+ }
+
+ private static void parseStructuredNameExtra(
+ Context context, AccountType accountType, RawContactDelta state, Bundle extras) {
+ // StructuredName
+ RawContactModifier.ensureKindExists(state, accountType, StructuredName.CONTENT_ITEM_TYPE);
+ final ValuesDelta child = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
+
+ final String name = extras.getString(Insert.NAME);
+ if (ContactsUtils.isGraphic(name)) {
+ final DataKind kind = accountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
+ boolean supportsDisplayName = false;
+ if (kind.fieldList != null) {
+ for (EditField field : kind.fieldList) {
+ if (StructuredName.DISPLAY_NAME.equals(field.column)) {
+ supportsDisplayName = true;
+ break;
+ }
+ }
+ }
+
+ if (supportsDisplayName) {
+ child.put(StructuredName.DISPLAY_NAME, name);
+ } else {
+ Uri uri = ContactsContract.AUTHORITY_URI.buildUpon()
+ .appendPath("complete_name")
+ .appendQueryParameter(StructuredName.DISPLAY_NAME, name)
+ .build();
+ Cursor cursor = context.getContentResolver().query(uri,
+ new String[]{
+ StructuredName.PREFIX,
+ StructuredName.GIVEN_NAME,
+ StructuredName.MIDDLE_NAME,
+ StructuredName.FAMILY_NAME,
+ StructuredName.SUFFIX,
+ }, null, null, null);
+
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ child.put(StructuredName.PREFIX, cursor.getString(0));
+ child.put(StructuredName.GIVEN_NAME, cursor.getString(1));
+ child.put(StructuredName.MIDDLE_NAME, cursor.getString(2));
+ child.put(StructuredName.FAMILY_NAME, cursor.getString(3));
+ child.put(StructuredName.SUFFIX, cursor.getString(4));
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ }
+ }
+
+ final String phoneticName = extras.getString(Insert.PHONETIC_NAME);
+ if (ContactsUtils.isGraphic(phoneticName)) {
+ StructuredNameDataItem dataItem = NameConverter.parsePhoneticName(phoneticName, null);
+ child.put(StructuredName.PHONETIC_FAMILY_NAME, dataItem.getPhoneticFamilyName());
+ child.put(StructuredName.PHONETIC_MIDDLE_NAME, dataItem.getPhoneticMiddleName());
+ child.put(StructuredName.PHONETIC_GIVEN_NAME, dataItem.getPhoneticGivenName());
+ }
+ }
+
+ private static void parseStructuredPostalExtra(
+ AccountType accountType, RawContactDelta state, Bundle extras) {
+ // StructuredPostal
+ final DataKind kind = accountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
+ final ValuesDelta child = parseExtras(state, kind, extras, Insert.POSTAL_TYPE,
+ Insert.POSTAL, StructuredPostal.FORMATTED_ADDRESS);
+ String address = child == null ? null
+ : child.getAsString(StructuredPostal.FORMATTED_ADDRESS);
+ if (!TextUtils.isEmpty(address)) {
+ boolean supportsFormatted = false;
+ if (kind.fieldList != null) {
+ for (EditField field : kind.fieldList) {
+ if (StructuredPostal.FORMATTED_ADDRESS.equals(field.column)) {
+ supportsFormatted = true;
+ break;
+ }
+ }
+ }
+
+ if (!supportsFormatted) {
+ child.put(StructuredPostal.STREET, address);
+ child.putNull(StructuredPostal.FORMATTED_ADDRESS);
+ }
+ }
+ }
+
+ private static void parseValues(
+ RawContactDelta state, AccountType accountType,
+ ArrayList<ContentValues> dataValueList) {
+ for (ContentValues values : dataValueList) {
+ String mimeType = values.getAsString(Data.MIMETYPE);
+ if (TextUtils.isEmpty(mimeType)) {
+ Log.e(TAG, "Mimetype is required. Ignoring: " + values);
+ continue;
+ }
+
+ // Won't override the contact name
+ if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ continue;
+ } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ values.remove(PhoneDataItem.KEY_FORMATTED_PHONE_NUMBER);
+ final Integer type = values.getAsInteger(Phone.TYPE);
+ // If the provided phone number provides a custom phone type but not a label,
+ // replace it with mobile (by default) to avoid the "Enter custom label" from
+ // popping up immediately upon entering the ContactEditorFragment
+ if (type != null && type == Phone.TYPE_CUSTOM &&
+ TextUtils.isEmpty(values.getAsString(Phone.LABEL))) {
+ values.put(Phone.TYPE, Phone.TYPE_MOBILE);
+ }
+ }
+
+ DataKind kind = accountType.getKindForMimetype(mimeType);
+ if (kind == null) {
+ Log.e(TAG, "Mimetype not supported for account type "
+ + accountType.getAccountTypeAndDataSet() + ". Ignoring: " + values);
+ continue;
+ }
+
+ ValuesDelta entry = ValuesDelta.fromAfter(values);
+ if (isEmpty(entry, kind)) {
+ continue;
+ }
+
+ ArrayList<ValuesDelta> entries = state.getMimeEntries(mimeType);
+
+ if ((kind.typeOverallMax != 1) || GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ // Check for duplicates
+ boolean addEntry = true;
+ int count = 0;
+ if (entries != null && entries.size() > 0) {
+ for (ValuesDelta delta : entries) {
+ if (!delta.isDelete()) {
+ if (areEqual(delta, values, kind)) {
+ addEntry = false;
+ break;
+ }
+ count++;
+ }
+ }
+ }
+
+ if (kind.typeOverallMax != -1 && count >= kind.typeOverallMax) {
+ Log.e(TAG, "Mimetype allows at most " + kind.typeOverallMax
+ + " entries. Ignoring: " + values);
+ addEntry = false;
+ }
+
+ if (addEntry) {
+ addEntry = adjustType(entry, entries, kind);
+ }
+
+ if (addEntry) {
+ state.addEntry(entry);
+ }
+ } else {
+ // Non-list entries should not be overridden
+ boolean addEntry = true;
+ if (entries != null && entries.size() > 0) {
+ for (ValuesDelta delta : entries) {
+ if (!delta.isDelete() && !isEmpty(delta, kind)) {
+ addEntry = false;
+ break;
+ }
+ }
+ if (addEntry) {
+ for (ValuesDelta delta : entries) {
+ delta.markDeleted();
+ }
+ }
+ }
+
+ if (addEntry) {
+ addEntry = adjustType(entry, entries, kind);
+ }
+
+ if (addEntry) {
+ state.addEntry(entry);
+ } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType)){
+ // Note is most likely to contain large amounts of text
+ // that we don't want to drop on the ground.
+ for (ValuesDelta delta : entries) {
+ if (!isEmpty(delta, kind)) {
+ delta.put(Note.NOTE, delta.getAsString(Note.NOTE) + "\n"
+ + values.getAsString(Note.NOTE));
+ break;
+ }
+ }
+ } else {
+ Log.e(TAG, "Will not override mimetype " + mimeType + ". Ignoring: "
+ + values);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if the data kind allows addition of another entry (e.g. Exchange only
+ * supports two "work" phone numbers). If not, tries to switch to one of the
+ * unused types. If successful, returns true.
+ */
+ private static boolean adjustType(
+ ValuesDelta entry, ArrayList<ValuesDelta> entries, DataKind kind) {
+ if (kind.typeColumn == null || kind.typeList == null || kind.typeList.size() == 0) {
+ return true;
+ }
+
+ Integer typeInteger = entry.getAsInteger(kind.typeColumn);
+ int type = typeInteger != null ? typeInteger : kind.typeList.get(0).rawValue;
+
+ if (isTypeAllowed(type, entries, kind)) {
+ entry.put(kind.typeColumn, type);
+ return true;
+ }
+
+ // Specified type is not allowed - choose the first available type that is allowed
+ int size = kind.typeList.size();
+ for (int i = 0; i < size; i++) {
+ EditType editType = kind.typeList.get(i);
+ if (isTypeAllowed(editType.rawValue, entries, kind)) {
+ entry.put(kind.typeColumn, editType.rawValue);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if a new entry of the specified type can be added to the raw
+ * contact. For example, Exchange only supports two "work" phone numbers, so
+ * addition of a third would not be allowed.
+ */
+ private static boolean isTypeAllowed(int type, ArrayList<ValuesDelta> entries, DataKind kind) {
+ int max = 0;
+ int size = kind.typeList.size();
+ for (int i = 0; i < size; i++) {
+ EditType editType = kind.typeList.get(i);
+ if (editType.rawValue == type) {
+ max = editType.specificMax;
+ break;
+ }
+ }
+
+ if (max == 0) {
+ // This type is not allowed at all
+ return false;
+ }
+
+ if (max == -1) {
+ // Unlimited instances of this type are allowed
+ return true;
+ }
+
+ return getEntryCountByType(entries, kind.typeColumn, type) < max;
+ }
+
+ /**
+ * Counts occurrences of the specified type in the supplied entry list.
+ *
+ * @return The count of occurrences of the type in the entry list. 0 if entries is
+ * {@literal null}
+ */
+ private static int getEntryCountByType(ArrayList<ValuesDelta> entries, String typeColumn,
+ int type) {
+ int count = 0;
+ if (entries != null) {
+ for (ValuesDelta entry : entries) {
+ Integer typeInteger = entry.getAsInteger(typeColumn);
+ if (typeInteger != null && typeInteger == type) {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Attempt to parse legacy {@link Insert#IM_PROTOCOL} values, replacing them
+ * with updated values.
+ */
+ @SuppressWarnings("deprecation")
+ 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 RawContactDelta}. 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 ValuesDelta parseExtras(RawContactDelta state, DataKind kind, Bundle extras,
+ String typeExtra, String valueExtra, String valueColumn) {
+ final CharSequence value = extras.getCharSequence(valueExtra);
+
+ // Bail early if account type doesn't handle this MIME type
+ if (kind == null) return null;
+
+ // Bail when can't insert type, or value missing
+ final boolean canInsert = RawContactModifier.canInsert(state, kind);
+ final boolean validValue = (value != null && TextUtils.isGraphic(value));
+ if (!validValue || !canInsert) return null;
+
+ // 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 = RawContactModifier.getBestValidType(state, kind, true, typeValue);
+
+ // Create data row and fill with value
+ final ValuesDelta child = RawContactModifier.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);
+ }
+
+ return child;
+ }
+
+ /**
+ * Generic mime types with type support (e.g. TYPE_HOME).
+ * Here, "type support" means if the data kind has CommonColumns#TYPE or not. Data kinds which
+ * have their own migrate methods aren't listed here.
+ */
+ private static final Set<String> sGenericMimeTypesWithTypeSupport = new HashSet<String>(
+ Arrays.asList(Phone.CONTENT_ITEM_TYPE,
+ Email.CONTENT_ITEM_TYPE,
+ Im.CONTENT_ITEM_TYPE,
+ Nickname.CONTENT_ITEM_TYPE,
+ Website.CONTENT_ITEM_TYPE,
+ Relation.CONTENT_ITEM_TYPE,
+ SipAddress.CONTENT_ITEM_TYPE));
+ private static final Set<String> sGenericMimeTypesWithoutTypeSupport = new HashSet<String>(
+ Arrays.asList(Organization.CONTENT_ITEM_TYPE,
+ Note.CONTENT_ITEM_TYPE,
+ Photo.CONTENT_ITEM_TYPE,
+ GroupMembership.CONTENT_ITEM_TYPE));
+ // CommonColumns.TYPE cannot be accessed as it is protected interface, so use
+ // Phone.TYPE instead.
+ private static final String COLUMN_FOR_TYPE = Phone.TYPE;
+ private static final String COLUMN_FOR_LABEL = Phone.LABEL;
+ private static final int TYPE_CUSTOM = Phone.TYPE_CUSTOM;
+
+ /**
+ * Migrates old RawContactDelta to newly created one with a new restriction supplied from
+ * newAccountType.
+ *
+ * This is only for account switch during account creation (which must be insert operation).
+ */
+ public static void migrateStateForNewContact(Context context,
+ RawContactDelta oldState, RawContactDelta newState,
+ AccountType oldAccountType, AccountType newAccountType) {
+ if (newAccountType == oldAccountType) {
+ // Just copying all data in oldState isn't enough, but we can still rely on a lot of
+ // shortcuts.
+ for (DataKind kind : newAccountType.getSortedDataKinds()) {
+ final String mimeType = kind.mimeType;
+ // The fields with short/long form capability must be treated properly.
+ if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ migrateStructuredName(context, oldState, newState, kind);
+ } else {
+ List<ValuesDelta> entryList = oldState.getMimeEntries(mimeType);
+ if (entryList != null && !entryList.isEmpty()) {
+ for (ValuesDelta entry : entryList) {
+ ContentValues values = entry.getAfter();
+ if (values != null) {
+ newState.addEntry(ValuesDelta.fromAfter(values));
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // Migrate data supported by the new account type.
+ // All the other data inside oldState are silently dropped.
+ for (DataKind kind : newAccountType.getSortedDataKinds()) {
+ if (!kind.editable) continue;
+ final String mimeType = kind.mimeType;
+ if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)
+ || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
+ // Ignore pseudo data.
+ continue;
+ } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ migrateStructuredName(context, oldState, newState, kind);
+ } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ migratePostal(oldState, newState, kind);
+ } else if (Event.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ migrateEvent(oldState, newState, kind, null /* default Year */);
+ } else if (sGenericMimeTypesWithoutTypeSupport.contains(mimeType)) {
+ migrateGenericWithoutTypeColumn(oldState, newState, kind);
+ } else if (sGenericMimeTypesWithTypeSupport.contains(mimeType)) {
+ migrateGenericWithTypeColumn(oldState, newState, kind);
+ } else {
+ throw new IllegalStateException("Unexpected editable mime-type: " + mimeType);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks {@link DataKind#isList} and {@link DataKind#typeOverallMax}, and restricts
+ * the number of entries (ValuesDelta) inside newState.
+ */
+ private static ArrayList<ValuesDelta> ensureEntryMaxSize(RawContactDelta newState,
+ DataKind kind, ArrayList<ValuesDelta> mimeEntries) {
+ if (mimeEntries == null) {
+ return null;
+ }
+
+ final int typeOverallMax = kind.typeOverallMax;
+ if (typeOverallMax >= 0 && (mimeEntries.size() > typeOverallMax)) {
+ ArrayList<ValuesDelta> newMimeEntries = new ArrayList<ValuesDelta>(typeOverallMax);
+ for (int i = 0; i < typeOverallMax; i++) {
+ newMimeEntries.add(mimeEntries.get(i));
+ }
+ mimeEntries = newMimeEntries;
+ }
+ return mimeEntries;
+ }
+
+ /** @hide Public only for testing. */
+ public static void migrateStructuredName(
+ Context context, RawContactDelta oldState, RawContactDelta newState,
+ DataKind newDataKind) {
+ final ContentValues values =
+ oldState.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE).getAfter();
+ if (values == null) {
+ return;
+ }
+
+ boolean supportDisplayName = false;
+ boolean supportPhoneticFullName = false;
+ boolean supportPhoneticFamilyName = false;
+ boolean supportPhoneticMiddleName = false;
+ boolean supportPhoneticGivenName = false;
+ for (EditField editField : newDataKind.fieldList) {
+ if (StructuredName.DISPLAY_NAME.equals(editField.column)) {
+ supportDisplayName = true;
+ }
+ if (DataKind.PSEUDO_COLUMN_PHONETIC_NAME.equals(editField.column)) {
+ supportPhoneticFullName = true;
+ }
+ if (StructuredName.PHONETIC_FAMILY_NAME.equals(editField.column)) {
+ supportPhoneticFamilyName = true;
+ }
+ if (StructuredName.PHONETIC_MIDDLE_NAME.equals(editField.column)) {
+ supportPhoneticMiddleName = true;
+ }
+ if (StructuredName.PHONETIC_GIVEN_NAME.equals(editField.column)) {
+ supportPhoneticGivenName = true;
+ }
+ }
+
+ // DISPLAY_NAME <-> PREFIX, GIVEN_NAME, MIDDLE_NAME, FAMILY_NAME, SUFFIX
+ final String displayName = values.getAsString(StructuredName.DISPLAY_NAME);
+ if (!TextUtils.isEmpty(displayName)) {
+ if (!supportDisplayName) {
+ // Old data has a display name, while the new account doesn't allow it.
+ NameConverter.displayNameToStructuredName(context, displayName, values);
+
+ // We don't want to migrate unseen data which may confuse users after the creation.
+ values.remove(StructuredName.DISPLAY_NAME);
+ }
+ } else {
+ if (supportDisplayName) {
+ // Old data does not have display name, while the new account requires it.
+ values.put(StructuredName.DISPLAY_NAME,
+ NameConverter.structuredNameToDisplayName(context, values));
+ for (String field : NameConverter.STRUCTURED_NAME_FIELDS) {
+ values.remove(field);
+ }
+ }
+ }
+
+ // Phonetic (full) name <-> PHONETIC_FAMILY_NAME, PHONETIC_MIDDLE_NAME, PHONETIC_GIVEN_NAME
+ final String phoneticFullName = values.getAsString(DataKind.PSEUDO_COLUMN_PHONETIC_NAME);
+ if (!TextUtils.isEmpty(phoneticFullName)) {
+ if (!supportPhoneticFullName) {
+ // Old data has a phonetic (full) name, while the new account doesn't allow it.
+ final StructuredNameDataItem tmpItem =
+ NameConverter.parsePhoneticName(phoneticFullName, null);
+ values.remove(DataKind.PSEUDO_COLUMN_PHONETIC_NAME);
+ if (supportPhoneticFamilyName) {
+ values.put(StructuredName.PHONETIC_FAMILY_NAME,
+ tmpItem.getPhoneticFamilyName());
+ } else {
+ values.remove(StructuredName.PHONETIC_FAMILY_NAME);
+ }
+ if (supportPhoneticMiddleName) {
+ values.put(StructuredName.PHONETIC_MIDDLE_NAME,
+ tmpItem.getPhoneticMiddleName());
+ } else {
+ values.remove(StructuredName.PHONETIC_MIDDLE_NAME);
+ }
+ if (supportPhoneticGivenName) {
+ values.put(StructuredName.PHONETIC_GIVEN_NAME,
+ tmpItem.getPhoneticGivenName());
+ } else {
+ values.remove(StructuredName.PHONETIC_GIVEN_NAME);
+ }
+ }
+ } else {
+ if (supportPhoneticFullName) {
+ // Old data does not have a phonetic (full) name, while the new account requires it.
+ values.put(DataKind.PSEUDO_COLUMN_PHONETIC_NAME,
+ NameConverter.buildPhoneticName(
+ values.getAsString(StructuredName.PHONETIC_FAMILY_NAME),
+ values.getAsString(StructuredName.PHONETIC_MIDDLE_NAME),
+ values.getAsString(StructuredName.PHONETIC_GIVEN_NAME)));
+ }
+ if (!supportPhoneticFamilyName) {
+ values.remove(StructuredName.PHONETIC_FAMILY_NAME);
+ }
+ if (!supportPhoneticMiddleName) {
+ values.remove(StructuredName.PHONETIC_MIDDLE_NAME);
+ }
+ if (!supportPhoneticGivenName) {
+ values.remove(StructuredName.PHONETIC_GIVEN_NAME);
+ }
+ }
+
+ newState.addEntry(ValuesDelta.fromAfter(values));
+ }
+
+ /** @hide Public only for testing. */
+ public static void migratePostal(RawContactDelta oldState, RawContactDelta newState,
+ DataKind newDataKind) {
+ final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind,
+ oldState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE));
+ if (mimeEntries == null || mimeEntries.isEmpty()) {
+ return;
+ }
+
+ boolean supportFormattedAddress = false;
+ boolean supportStreet = false;
+ final String firstColumn = newDataKind.fieldList.get(0).column;
+ for (EditField editField : newDataKind.fieldList) {
+ if (StructuredPostal.FORMATTED_ADDRESS.equals(editField.column)) {
+ supportFormattedAddress = true;
+ }
+ if (StructuredPostal.STREET.equals(editField.column)) {
+ supportStreet = true;
+ }
+ }
+
+ final Set<Integer> supportedTypes = new HashSet<Integer>();
+ if (newDataKind.typeList != null && !newDataKind.typeList.isEmpty()) {
+ for (EditType editType : newDataKind.typeList) {
+ supportedTypes.add(editType.rawValue);
+ }
+ }
+
+ for (ValuesDelta entry : mimeEntries) {
+ final ContentValues values = entry.getAfter();
+ if (values == null) {
+ continue;
+ }
+ final Integer oldType = values.getAsInteger(StructuredPostal.TYPE);
+ if (!supportedTypes.contains(oldType)) {
+ int defaultType;
+ if (newDataKind.defaultValues != null) {
+ defaultType = newDataKind.defaultValues.getAsInteger(StructuredPostal.TYPE);
+ } else {
+ defaultType = newDataKind.typeList.get(0).rawValue;
+ }
+ values.put(StructuredPostal.TYPE, defaultType);
+ if (oldType != null && oldType == StructuredPostal.TYPE_CUSTOM) {
+ values.remove(StructuredPostal.LABEL);
+ }
+ }
+
+ final String formattedAddress = values.getAsString(StructuredPostal.FORMATTED_ADDRESS);
+ if (!TextUtils.isEmpty(formattedAddress)) {
+ if (!supportFormattedAddress) {
+ // Old data has a formatted address, while the new account doesn't allow it.
+ values.remove(StructuredPostal.FORMATTED_ADDRESS);
+
+ // Unlike StructuredName we don't have logic to split it, so first
+ // try to use street field and. If the new account doesn't have one,
+ // then select first one anyway.
+ if (supportStreet) {
+ values.put(StructuredPostal.STREET, formattedAddress);
+ } else {
+ values.put(firstColumn, formattedAddress);
+ }
+ }
+ } else {
+ if (supportFormattedAddress) {
+ // Old data does not have formatted address, while the new account requires it.
+ // Unlike StructuredName we don't have logic to join multiple address values.
+ // Use poor join heuristics for now.
+ String[] structuredData;
+ final boolean useJapaneseOrder =
+ Locale.JAPANESE.getLanguage().equals(Locale.getDefault().getLanguage());
+ if (useJapaneseOrder) {
+ structuredData = new String[] {
+ values.getAsString(StructuredPostal.COUNTRY),
+ values.getAsString(StructuredPostal.POSTCODE),
+ values.getAsString(StructuredPostal.REGION),
+ values.getAsString(StructuredPostal.CITY),
+ values.getAsString(StructuredPostal.NEIGHBORHOOD),
+ values.getAsString(StructuredPostal.STREET),
+ values.getAsString(StructuredPostal.POBOX) };
+ } else {
+ structuredData = new String[] {
+ values.getAsString(StructuredPostal.POBOX),
+ values.getAsString(StructuredPostal.STREET),
+ values.getAsString(StructuredPostal.NEIGHBORHOOD),
+ values.getAsString(StructuredPostal.CITY),
+ values.getAsString(StructuredPostal.REGION),
+ values.getAsString(StructuredPostal.POSTCODE),
+ values.getAsString(StructuredPostal.COUNTRY) };
+ }
+ final StringBuilder builder = new StringBuilder();
+ for (String elem : structuredData) {
+ if (!TextUtils.isEmpty(elem)) {
+ builder.append(elem + "\n");
+ }
+ }
+ values.put(StructuredPostal.FORMATTED_ADDRESS, builder.toString());
+
+ values.remove(StructuredPostal.POBOX);
+ values.remove(StructuredPostal.STREET);
+ values.remove(StructuredPostal.NEIGHBORHOOD);
+ values.remove(StructuredPostal.CITY);
+ values.remove(StructuredPostal.REGION);
+ values.remove(StructuredPostal.POSTCODE);
+ values.remove(StructuredPostal.COUNTRY);
+ }
+ }
+
+ newState.addEntry(ValuesDelta.fromAfter(values));
+ }
+ }
+
+ /** @hide Public only for testing. */
+ public static void migrateEvent(RawContactDelta oldState, RawContactDelta newState,
+ DataKind newDataKind, Integer defaultYear) {
+ final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind,
+ oldState.getMimeEntries(Event.CONTENT_ITEM_TYPE));
+ if (mimeEntries == null || mimeEntries.isEmpty()) {
+ return;
+ }
+
+ final SparseArray<EventEditType> allowedTypes = new SparseArray<EventEditType>();
+ for (EditType editType : newDataKind.typeList) {
+ allowedTypes.put(editType.rawValue, (EventEditType) editType);
+ }
+ for (ValuesDelta entry : mimeEntries) {
+ final ContentValues values = entry.getAfter();
+ if (values == null) {
+ continue;
+ }
+ final String dateString = values.getAsString(Event.START_DATE);
+ final Integer type = values.getAsInteger(Event.TYPE);
+ if (type != null && (allowedTypes.indexOfKey(type) >= 0)
+ && !TextUtils.isEmpty(dateString)) {
+ EventEditType suitableType = allowedTypes.get(type);
+
+ final ParsePosition position = new ParsePosition(0);
+ boolean yearOptional = false;
+ Date date = CommonDateUtils.DATE_AND_TIME_FORMAT.parse(dateString, position);
+ if (date == null) {
+ yearOptional = true;
+ date = CommonDateUtils.NO_YEAR_DATE_FORMAT.parse(dateString, position);
+ }
+ if (date != null) {
+ if (yearOptional && !suitableType.isYearOptional()) {
+ // The new EditType doesn't allow optional year. Supply default.
+ final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE,
+ Locale.US);
+ if (defaultYear == null) {
+ defaultYear = calendar.get(Calendar.YEAR);
+ }
+ calendar.setTime(date);
+ final int month = calendar.get(Calendar.MONTH);
+ final int day = calendar.get(Calendar.DAY_OF_MONTH);
+ // Exchange requires 8:00 for birthdays
+ calendar.set(defaultYear, month, day,
+ CommonDateUtils.DEFAULT_HOUR, 0, 0);
+ values.put(Event.START_DATE,
+ CommonDateUtils.FULL_DATE_FORMAT.format(calendar.getTime()));
+ }
+ }
+ newState.addEntry(ValuesDelta.fromAfter(values));
+ } else {
+ // Just drop it.
+ }
+ }
+ }
+
+ /** @hide Public only for testing. */
+ public static void migrateGenericWithoutTypeColumn(
+ RawContactDelta oldState, RawContactDelta newState, DataKind newDataKind) {
+ final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind,
+ oldState.getMimeEntries(newDataKind.mimeType));
+ if (mimeEntries == null || mimeEntries.isEmpty()) {
+ return;
+ }
+
+ for (ValuesDelta entry : mimeEntries) {
+ ContentValues values = entry.getAfter();
+ if (values != null) {
+ newState.addEntry(ValuesDelta.fromAfter(values));
+ }
+ }
+ }
+
+ /** @hide Public only for testing. */
+ public static void migrateGenericWithTypeColumn(
+ RawContactDelta oldState, RawContactDelta newState, DataKind newDataKind) {
+ final ArrayList<ValuesDelta> mimeEntries = oldState.getMimeEntries(newDataKind.mimeType);
+ if (mimeEntries == null || mimeEntries.isEmpty()) {
+ return;
+ }
+
+ // Note that type specified with the old account may be invalid with the new account, while
+ // we want to preserve its data as much as possible. e.g. if a user typed a phone number
+ // with a type which is valid with an old account but not with a new account, the user
+ // probably wants to have the number with default type, rather than seeing complete data
+ // loss.
+ //
+ // Specifically, this method works as follows:
+ // 1. detect defaultType
+ // 2. prepare constants & variables for iteration
+ // 3. iterate over mimeEntries:
+ // 3.1 stop iteration if total number of mimeEntries reached typeOverallMax specified in
+ // DataKind
+ // 3.2 replace unallowed types with defaultType
+ // 3.3 check if the number of entries is below specificMax specified in AccountType
+
+ // Here, defaultType can be supplied in two ways
+ // - via kind.defaultValues
+ // - via kind.typeList.get(0).rawValue
+ Integer defaultType = null;
+ if (newDataKind.defaultValues != null) {
+ defaultType = newDataKind.defaultValues.getAsInteger(COLUMN_FOR_TYPE);
+ }
+ final Set<Integer> allowedTypes = new HashSet<Integer>();
+ // key: type, value: the number of entries allowed for the type (specificMax)
+ final SparseIntArray typeSpecificMaxMap = new SparseIntArray();
+ if (defaultType != null) {
+ allowedTypes.add(defaultType);
+ typeSpecificMaxMap.put(defaultType, -1);
+ }
+ // Note: typeList may be used in different purposes when defaultValues are specified.
+ // Especially in IM, typeList contains available protocols (e.g. PROTOCOL_GOOGLE_TALK)
+ // instead of "types" which we want to treate here (e.g. TYPE_HOME). So we don't add
+ // anything other than defaultType into allowedTypes and typeSpecificMapMax.
+ if (!Im.CONTENT_ITEM_TYPE.equals(newDataKind.mimeType) &&
+ newDataKind.typeList != null && !newDataKind.typeList.isEmpty()) {
+ for (EditType editType : newDataKind.typeList) {
+ allowedTypes.add(editType.rawValue);
+ typeSpecificMaxMap.put(editType.rawValue, editType.specificMax);
+ }
+ if (defaultType == null) {
+ defaultType = newDataKind.typeList.get(0).rawValue;
+ }
+ }
+
+ if (defaultType == null) {
+ Log.w(TAG, "Default type isn't available for mimetype " + newDataKind.mimeType);
+ }
+
+ final int typeOverallMax = newDataKind.typeOverallMax;
+
+ // key: type, value: the number of current entries.
+ final SparseIntArray currentEntryCount = new SparseIntArray();
+ int totalCount = 0;
+
+ for (ValuesDelta entry : mimeEntries) {
+ if (typeOverallMax != -1 && totalCount >= typeOverallMax) {
+ break;
+ }
+
+ final ContentValues values = entry.getAfter();
+ if (values == null) {
+ continue;
+ }
+
+ final Integer oldType = entry.getAsInteger(COLUMN_FOR_TYPE);
+ final Integer typeForNewAccount;
+ if (!allowedTypes.contains(oldType)) {
+ // The new account doesn't support the type.
+ if (defaultType != null) {
+ typeForNewAccount = defaultType.intValue();
+ values.put(COLUMN_FOR_TYPE, defaultType.intValue());
+ if (oldType != null && oldType == TYPE_CUSTOM) {
+ values.remove(COLUMN_FOR_LABEL);
+ }
+ } else {
+ typeForNewAccount = null;
+ values.remove(COLUMN_FOR_TYPE);
+ }
+ } else {
+ typeForNewAccount = oldType;
+ }
+ if (typeForNewAccount != null) {
+ final int specificMax = typeSpecificMaxMap.get(typeForNewAccount, 0);
+ if (specificMax >= 0) {
+ final int currentCount = currentEntryCount.get(typeForNewAccount, 0);
+ if (currentCount >= specificMax) {
+ continue;
+ }
+ currentEntryCount.put(typeForNewAccount, currentCount + 1);
+ }
+ }
+ newState.addEntry(ValuesDelta.fromAfter(values));
+ totalCount++;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/model/ValuesDelta.java b/src/com/android/contacts/common/model/ValuesDelta.java
new file mode 100644
index 0000000..9023709
--- /dev/null
+++ b/src/com/android/contacts/common/model/ValuesDelta.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2012 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.common.model;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.BaseColumns;
+import android.provider.ContactsContract;
+
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.model.BuilderWrapper;
+import com.android.contacts.common.testing.NeededForTesting;
+import com.google.common.collect.Sets;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Type of {@link android.content.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 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(android.content.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;
+ }
+
+ @NeededForTesting
+ public ContentValues getAfter() {
+ return mAfter;
+ }
+
+ public boolean containsKey(String key) {
+ return ((mAfter != null && mAfter.containsKey(key)) ||
+ (mBefore != null && mBefore.containsKey(key)));
+ }
+
+ 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 boolean isChanged(String key) {
+ if (mAfter == null || !mAfter.containsKey(key)) {
+ return false;
+ }
+
+ Object newValue = mAfter.get(key);
+ Object oldValue = mBefore.get(key);
+
+ if (oldValue == null) {
+ return newValue != null;
+ }
+
+ return !oldValue.equals(newValue);
+ }
+
+ public String getMimetype() {
+ return getAsString(ContactsContract.Data.MIMETYPE);
+ }
+
+ public Long getId() {
+ return getAsLong(mIdColumn);
+ }
+
+ public void setIdColumn(String idColumn) {
+ mIdColumn = idColumn;
+ }
+
+ public boolean isPrimary() {
+ final Long isPrimary = getAsLong(ContactsContract.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(ContactsContract.Data.IS_SUPER_PRIMARY);
+ return isSuperPrimary == null ? false : isSuperPrimary != 0;
+ }
+
+ public boolean beforeExists() {
+ return (mBefore != null && mBefore.containsKey(mIdColumn));
+ }
+
+ /**
+ * When "after" is present, then visible
+ */
+ public boolean isVisible() {
+ return (mAfter != null);
+ }
+
+ /**
+ * When "after" is wiped, action is "delete"
+ */
+ public boolean isDelete() {
+ return beforeExists() && (mAfter == null);
+ }
+
+ /**
+ * When no "before" or "after", is transient
+ */
+ public boolean isTransient() {
+ return (mBefore == null) && (mAfter == null);
+ }
+
+ /**
+ * When "after" has some changes, action is "update"
+ */
+ public boolean isUpdate() {
+ if (!beforeExists() || mAfter == null || mAfter.size() == 0) {
+ return false;
+ }
+ for (String key : mAfter.keySet()) {
+ Object newValue = mAfter.get(key);
+ Object oldValue = mBefore.get(key);
+ if (oldValue == null) {
+ if (newValue != null) {
+ return true;
+ }
+ } else if (!oldValue.equals(newValue)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * When "after" has no changes, action is no-op
+ */
+ public boolean isNoop() {
+ return beforeExists() && (mAfter != null && mAfter.size() == 0);
+ }
+
+ /**
+ * When no "before" id, and has "after", action is "insert"
+ */
+ public boolean isInsert() {
+ 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);
+ }
+
+ public void put(String key, long value) {
+ ensureUpdate();
+ mAfter.put(key, value);
+ }
+
+ public void putNull(String key) {
+ ensureUpdate();
+ mAfter.putNull(key);
+ }
+
+ public void copyStringFrom(ValuesDelta from, String key) {
+ ensureUpdate();
+ if (containsKey(key) || from.containsKey(key)) {
+ put(key, from.getAsString(key));
+ }
+ }
+
+ /**
+ * 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(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID)) {
+ // Clear to avoid double-definitions, and prefer rows
+ values.remove(ContactsContract.CommonDataKinds.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("{ ");
+ builder.append("IdColumn=");
+ builder.append(mIdColumn);
+ builder.append(", FromTemplate=");
+ builder.append(mFromTemplate);
+ 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 android.content.ContentProviderOperation} that will transform our
+ * "before" state into our "after" state, using insert, update, or
+ * delete as needed.
+ */
+ public ContentProviderOperation.Builder buildDiff(Uri targetUri) {
+ return buildDiffHelper(targetUri);
+ }
+
+ /**
+ * For compatibility purpose.
+ */
+ public BuilderWrapper buildDiffWrapper(Uri targetUri) {
+ final ContentProviderOperation.Builder builder = buildDiffHelper(targetUri);
+ BuilderWrapper bw = null;
+ if (isInsert()) {
+ bw = new BuilderWrapper(builder, CompatUtils.TYPE_INSERT);
+ } else if (isDelete()) {
+ bw = new BuilderWrapper(builder, CompatUtils.TYPE_DELETE);
+ } else if (isUpdate()) {
+ bw = new BuilderWrapper(builder, CompatUtils.TYPE_UPDATE);
+ }
+ return bw;
+ }
+
+ private ContentProviderOperation.Builder buildDiffHelper(Uri targetUri) {
+ ContentProviderOperation.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) {
+ final ClassLoader loader = getClass().getClassLoader();
+ mBefore = source.<ContentValues> readParcelable(loader);
+ mAfter = source.<ContentValues> readParcelable(loader);
+ mIdColumn = source.readString();
+ }
+
+ public static final Creator<ValuesDelta> CREATOR = new 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];
+ }
+ };
+
+ public void setGroupRowId(long groupId) {
+ put(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId);
+ }
+
+ public Long getGroupRowId() {
+ return getAsLong(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID);
+ }
+
+ public void setPhoto(byte[] value) {
+ put(ContactsContract.CommonDataKinds.Photo.PHOTO, value);
+ }
+
+ public byte[] getPhoto() {
+ return getAsByteArray(ContactsContract.CommonDataKinds.Photo.PHOTO);
+ }
+
+ public void setSuperPrimary(boolean val) {
+ if (val) {
+ put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
+ } else {
+ put(ContactsContract.Data.IS_SUPER_PRIMARY, 0);
+ }
+ }
+
+ public void setPhoneticFamilyName(String value) {
+ put(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_FAMILY_NAME, value);
+ }
+
+ public void setPhoneticMiddleName(String value) {
+ put(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_MIDDLE_NAME, value);
+ }
+
+ public void setPhoneticGivenName(String value) {
+ put(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_GIVEN_NAME, value);
+ }
+
+ public String getPhoneticFamilyName() {
+ return getAsString(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_FAMILY_NAME);
+ }
+
+ public String getPhoneticMiddleName() {
+ return getAsString(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_MIDDLE_NAME);
+ }
+
+ public String getPhoneticGivenName() {
+ return getAsString(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_GIVEN_NAME);
+ }
+
+ public String getDisplayName() {
+ return getAsString(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
+ }
+
+ public void setDisplayName(String name) {
+ if (name == null) {
+ putNull(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
+ } else {
+ put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
+ }
+ }
+
+ public void copyStructuredNameFieldsFrom(ValuesDelta name) {
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
+
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.PREFIX);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.SUFFIX);
+
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.PHONETIC_GIVEN_NAME);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.PHONETIC_MIDDLE_NAME);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.PHONETIC_FAMILY_NAME);
+
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.FULL_NAME_STYLE);
+ copyStringFrom(name, ContactsContract.Data.DATA11);
+ }
+
+ public String getPhoneNumber() {
+ return getAsString(ContactsContract.CommonDataKinds.Phone.NUMBER);
+ }
+
+ public String getPhoneNormalizedNumber() {
+ return getAsString(ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER);
+ }
+
+ public boolean hasPhoneType() {
+ return getPhoneType() != null;
+ }
+
+ public Integer getPhoneType() {
+ return getAsInteger(ContactsContract.CommonDataKinds.Phone.TYPE);
+ }
+
+ public String getPhoneLabel() {
+ return getAsString(ContactsContract.CommonDataKinds.Phone.LABEL);
+ }
+
+ public String getEmailData() {
+ return getAsString(ContactsContract.CommonDataKinds.Email.DATA);
+ }
+
+ public boolean hasEmailType() {
+ return getEmailType() != null;
+ }
+
+ public Integer getEmailType() {
+ return getAsInteger(ContactsContract.CommonDataKinds.Email.TYPE);
+ }
+
+ public String getEmailLabel() {
+ return getAsString(ContactsContract.CommonDataKinds.Email.LABEL);
+ }
+}
diff --git a/src/com/android/contacts/common/model/account/AccountType.java b/src/com/android/contacts/common/model/account/AccountType.java
new file mode 100644
index 0000000..8b50d79
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/AccountType.java
@@ -0,0 +1,526 @@
+/*
+ * 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.common.model.account;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.view.inputmethod.EditorInfo;
+import android.widget.EditText;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.text.Collator;
+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 AccountType {
+ private static final String TAG = "AccountType";
+
+ /**
+ * The {@link RawContacts#ACCOUNT_TYPE} these constraints apply to.
+ */
+ public String accountType = null;
+
+ /**
+ * The {@link RawContacts#DATA_SET} these constraints apply to.
+ */
+ public String dataSet = null;
+
+ /**
+ * Package that resources should be loaded from. Will be null for embedded types, in which
+ * case resources are stored in this package itself.
+ *
+ * TODO Clean up {@link #resourcePackageName}, {@link #syncAdapterPackageName} and
+ * {@link #getViewContactNotifyServicePackageName()}.
+ *
+ * There's the following invariants:
+ * - {@link #syncAdapterPackageName} is always set to the actual sync adapter package name.
+ * - {@link #resourcePackageName} too is set to the same value, unless {@link #isEmbedded()},
+ * in which case it'll be null.
+ * There's an unfortunate exception of {@link FallbackAccountType}. Even though it
+ * {@link #isEmbedded()}, but we set non-null to {@link #resourcePackageName} for unit tests.
+ */
+ public String resourcePackageName;
+ /**
+ * The package name for the authenticator (for the embedded types, i.e. Google and Exchange)
+ * or the sync adapter (for external type, including extensions).
+ */
+ public String syncAdapterPackageName;
+
+ public int titleRes;
+ public int iconRes;
+
+ /**
+ * 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();
+
+ protected boolean mIsInitialized;
+
+ protected static class DefinitionException extends Exception {
+ public DefinitionException(String message) {
+ super(message);
+ }
+
+ public DefinitionException(String message, Exception inner) {
+ super(message, inner);
+ }
+ }
+
+ /**
+ * Whether this account type was able to be fully initialized. This may be false if
+ * (for example) the package name associated with the account type could not be found.
+ */
+ public final boolean isInitialized() {
+ return mIsInitialized;
+ }
+
+ /**
+ * @return Whether this type is an "embedded" type. i.e. any of {@link FallbackAccountType},
+ * {@link GoogleAccountType} or {@link ExternalAccountType}.
+ *
+ * If an embedded type cannot be initialized (i.e. if {@link #isInitialized()} returns
+ * {@code false}) it's considered critical, and the application will crash. On the other
+ * hand if it's not an embedded type, we just skip loading the type.
+ */
+ public boolean isEmbedded() {
+ return true;
+ }
+
+ public boolean isExtension() {
+ return false;
+ }
+
+ /**
+ * @return True if contacts can be created and edited using this app. If false,
+ * there could still be an external editor as provided by
+ * {@link #getEditContactActivityClassName()} or {@link #getCreateContactActivityClassName()}
+ */
+ public abstract boolean areContactsWritable();
+
+ /**
+ * Returns an optional custom edit activity.
+ *
+ * Only makes sense for non-embedded account types.
+ * The activity class should reside in the sync adapter package as determined by
+ * {@link #syncAdapterPackageName}.
+ */
+ public String getEditContactActivityClassName() {
+ return null;
+ }
+
+ /**
+ * Returns an optional custom new contact activity.
+ *
+ * Only makes sense for non-embedded account types.
+ * The activity class should reside in the sync adapter package as determined by
+ * {@link #syncAdapterPackageName}.
+ */
+ public String getCreateContactActivityClassName() {
+ return null;
+ }
+
+ /**
+ * Returns an optional custom invite contact activity.
+ *
+ * Only makes sense for non-embedded account types.
+ * The activity class should reside in the sync adapter package as determined by
+ * {@link #syncAdapterPackageName}.
+ */
+ public String getInviteContactActivityClassName() {
+ return null;
+ }
+
+ /**
+ * Returns an optional service that can be launched whenever a contact is being looked at.
+ * This allows the sync adapter to provide more up-to-date information.
+ *
+ * The service class should reside in the sync adapter package as determined by
+ * {@link #getViewContactNotifyServicePackageName()}.
+ */
+ public String getViewContactNotifyServiceClassName() {
+ return null;
+ }
+
+ /**
+ * TODO This is way too hacky should be removed.
+ *
+ * This is introduced for {@link GoogleAccountType} where {@link #syncAdapterPackageName}
+ * is the authenticator package name but the notification service is in the sync adapter
+ * package. See {@link #resourcePackageName} -- we should clean up those.
+ */
+ public String getViewContactNotifyServicePackageName() {
+ return syncAdapterPackageName;
+ }
+
+ /** Returns an optional Activity string that can be used to view the group. */
+ public String getViewGroupActivity() {
+ return null;
+ }
+
+ public CharSequence getDisplayLabel(Context context) {
+ // Note this resource is defined in the sync adapter package, not resourcePackageName.
+ return getResourceText(context, syncAdapterPackageName, titleRes, accountType);
+ }
+
+ /**
+ * @return resource ID for the "invite contact" action label, or -1 if not defined.
+ */
+ protected int getInviteContactActionResId() {
+ return -1;
+ }
+
+ /**
+ * @return resource ID for the "view group" label, or -1 if not defined.
+ */
+ protected int getViewGroupLabelResId() {
+ return -1;
+ }
+
+ /**
+ * Returns {@link AccountTypeWithDataSet} for this type.
+ */
+ public AccountTypeWithDataSet getAccountTypeAndDataSet() {
+ return AccountTypeWithDataSet.get(accountType, dataSet);
+ }
+
+ /**
+ * Returns a list of additional package names that should be inspected as additional
+ * external account types. This allows for a primary account type to indicate other packages
+ * that may not be sync adapters but which still provide contact data, perhaps under a
+ * separate data set within the account.
+ */
+ public List<String> getExtensionPackageNames() {
+ return new ArrayList<String>();
+ }
+
+ /**
+ * Returns an optional custom label for the "invite contact" action, which will be shown on
+ * the contact card. (If not defined, returns null.)
+ */
+ public CharSequence getInviteContactActionLabel(Context context) {
+ // Note this resource is defined in the sync adapter package, not resourcePackageName.
+ return getResourceText(context, syncAdapterPackageName, getInviteContactActionResId(), "");
+ }
+
+ /**
+ * Returns a label for the "view group" action. If not defined, this falls back to our
+ * own "View Updates" string
+ */
+ public CharSequence getViewGroupLabel(Context context) {
+ // Note this resource is defined in the sync adapter package, not resourcePackageName.
+ final CharSequence customTitle =
+ getResourceText(context, syncAdapterPackageName, getViewGroupLabelResId(), null);
+
+ return customTitle == null
+ ? context.getText(R.string.view_updates_from_group)
+ : customTitle;
+ }
+
+ /**
+ * Return a string resource loaded from the given package (or the current package
+ * if {@code packageName} is null), unless {@code resId} is -1, in which case it returns
+ * {@code defaultValue}.
+ *
+ * (The behavior is undefined if the resource or package doesn't exist.)
+ */
+ @VisibleForTesting
+ static CharSequence getResourceText(Context context, String packageName, int resId,
+ String defaultValue) {
+ if (resId != -1 && packageName != null) {
+ final PackageManager pm = context.getPackageManager();
+ return pm.getText(packageName, resId, null);
+ } else if (resId != -1) {
+ return context.getText(resId);
+ } else {
+ return defaultValue;
+ }
+ }
+
+ public Drawable getDisplayIcon(Context context) {
+ return getDisplayIcon(context, titleRes, iconRes, syncAdapterPackageName);
+ }
+
+ public static Drawable getDisplayIcon(Context context, int titleRes, int iconRes,
+ String syncAdapterPackageName) {
+ if (titleRes != -1 && syncAdapterPackageName != null) {
+ final PackageManager pm = context.getPackageManager();
+ return pm.getDrawable(syncAdapterPackageName, iconRes, null);
+ } else if (titleRes != -1) {
+ return context.getResources().getDrawable(iconRes);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Whether or not groups created under this account type have editable membership lists.
+ */
+ abstract public boolean isGroupMembershipEditable();
+
+ /**
+ * {@link Comparator} to sort by {@link DataKind#weight}.
+ */
+ private static Comparator<DataKind> sWeightComparator = new Comparator<DataKind>() {
+ @Override
+ 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.
+ */
+ 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) throws DefinitionException {
+ if (kind.mimeType == null) {
+ throw new DefinitionException("null is not a valid mime type");
+ }
+ if (mMimeKinds.get(kind.mimeType) != null) {
+ throw new DefinitionException(
+ "mime type '" + kind.mimeType + "' is already registered");
+ }
+
+ kind.resourcePackageName = this.resourcePackageName;
+ this.mKinds.add(kind);
+ this.mMimeKinds.put(kind.mimeType, kind);
+ return kind;
+ }
+
+ /**
+ * 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 boolean secondary;
+ /**
+ * The number of entries allowed for the type. -1 if not specified.
+ * @see DataKind#typeOverallMax
+ */
+ 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;
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName()
+ + " rawValue=" + rawValue
+ + " labelRes=" + labelRes
+ + " secondary=" + secondary
+ + " specificMax=" + specificMax
+ + " customColumn=" + customColumn;
+ }
+ }
+
+ public static class EventEditType extends EditType {
+ private boolean mYearOptional;
+
+ public EventEditType(int rawValue, int labelRes) {
+ super(rawValue, labelRes);
+ }
+
+ public boolean isYearOptional() {
+ return mYearOptional;
+ }
+
+ public EventEditType setYearOptional(boolean yearOptional) {
+ mYearOptional = yearOptional;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " mYearOptional=" + mYearOptional;
+ }
+ }
+
+ /**
+ * 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 final class EditField {
+ public String column;
+ public int titleRes;
+ public int inputType;
+ public int minLines;
+ public boolean optional;
+ public boolean shortForm;
+ public boolean longForm;
+
+ 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;
+ }
+
+ public EditField setShortForm(boolean shortForm) {
+ this.shortForm = shortForm;
+ return this;
+ }
+
+ public EditField setLongForm(boolean longForm) {
+ this.longForm = longForm;
+ return this;
+ }
+
+ public EditField setMinLines(int minLines) {
+ this.minLines = minLines;
+ return this;
+ }
+
+ public boolean isMultiLine() {
+ return (inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) != 0;
+ }
+
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + ":"
+ + " column=" + column
+ + " titleRes=" + titleRes
+ + " inputType=" + inputType
+ + " minLines=" + minLines
+ + " optional=" + optional
+ + " shortForm=" + shortForm
+ + " longForm=" + longForm;
+ }
+ }
+
+ /**
+ * Generic method of inflating a given {@link ContentValues} 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, ContentValues values);
+ }
+
+ /**
+ * Compare two {@link AccountType} by their {@link AccountType#getDisplayLabel} with the
+ * current locale.
+ */
+ public static class DisplayLabelComparator implements Comparator<AccountType> {
+ private final Context mContext;
+ /** {@link Comparator} for the current locale. */
+ private final Collator mCollator = Collator.getInstance();
+
+ public DisplayLabelComparator(Context context) {
+ mContext = context;
+ }
+
+ private String getDisplayLabel(AccountType type) {
+ CharSequence label = type.getDisplayLabel(mContext);
+ return (label == null) ? "" : label.toString();
+ }
+
+ @Override
+ public int compare(AccountType lhs, AccountType rhs) {
+ return mCollator.compare(getDisplayLabel(lhs), getDisplayLabel(rhs));
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/model/account/AccountTypeWithDataSet.java b/src/com/android/contacts/common/model/account/AccountTypeWithDataSet.java
new file mode 100644
index 0000000..f6bcf24
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/AccountTypeWithDataSet.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2011 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.common.model.account;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
+
+import com.google.common.base.Objects;
+
+
+/**
+ * Encapsulates an "account type" string and a "data set" string.
+ */
+public class AccountTypeWithDataSet {
+
+ private static final String[] ID_PROJECTION = new String[] {BaseColumns._ID};
+ private static final Uri RAW_CONTACTS_URI_LIMIT_1 = RawContacts.CONTENT_URI.buildUpon()
+ .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, "1").build();
+
+ /** account type. Can be null for fallback type. */
+ public final String accountType;
+
+ /** dataSet may be null, but never be "". */
+ public final String dataSet;
+
+ private AccountTypeWithDataSet(String accountType, String dataSet) {
+ this.accountType = TextUtils.isEmpty(accountType) ? null : accountType;
+ this.dataSet = TextUtils.isEmpty(dataSet) ? null : dataSet;
+ }
+
+ public static AccountTypeWithDataSet get(String accountType, String dataSet) {
+ return new AccountTypeWithDataSet(accountType, dataSet);
+ }
+
+ /**
+ * Return true if there are any contacts in the database with this account type and data set.
+ * Touches DB. Don't use in the UI thread.
+ */
+ public boolean hasData(Context context) {
+ final String BASE_SELECTION = RawContacts.ACCOUNT_TYPE + " = ?";
+ final String selection;
+ final String[] args;
+ if (TextUtils.isEmpty(dataSet)) {
+ selection = BASE_SELECTION + " AND " + RawContacts.DATA_SET + " IS NULL";
+ args = new String[] {accountType};
+ } else {
+ selection = BASE_SELECTION + " AND " + RawContacts.DATA_SET + " = ?";
+ args = new String[] {accountType, dataSet};
+ }
+
+ final Cursor c = context.getContentResolver().query(RAW_CONTACTS_URI_LIMIT_1,
+ ID_PROJECTION, selection, args, null);
+ if (c == null) return false;
+ try {
+ return c.moveToFirst();
+ } finally {
+ c.close();
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof AccountTypeWithDataSet)) return false;
+
+ AccountTypeWithDataSet other = (AccountTypeWithDataSet) o;
+ return Objects.equal(accountType, other.accountType)
+ && Objects.equal(dataSet, other.dataSet);
+ }
+
+ @Override
+ public int hashCode() {
+ return (accountType == null ? 0 : accountType.hashCode())
+ ^ (dataSet == null ? 0 : dataSet.hashCode());
+ }
+
+ @Override
+ public String toString() {
+ return "[" + accountType + "/" + dataSet + "]";
+ }
+}
diff --git a/src/com/android/contacts/common/model/account/AccountWithDataSet.java b/src/com/android/contacts/common/model/account/AccountWithDataSet.java
new file mode 100644
index 0000000..5947647
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/AccountWithDataSet.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2011 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.common.model.account;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.provider.BaseColumns;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * Wrapper for an account that includes a data set (which may be null).
+ */
+public class AccountWithDataSet implements Parcelable {
+ private static final String STRINGIFY_SEPARATOR = "\u0001";
+ private static final String ARRAY_STRINGIFY_SEPARATOR = "\u0002";
+
+ private static final Pattern STRINGIFY_SEPARATOR_PAT =
+ Pattern.compile(Pattern.quote(STRINGIFY_SEPARATOR));
+ private static final Pattern ARRAY_STRINGIFY_SEPARATOR_PAT =
+ Pattern.compile(Pattern.quote(ARRAY_STRINGIFY_SEPARATOR));
+
+ public final String name;
+ public final String type;
+ public final String dataSet;
+ private final AccountTypeWithDataSet mAccountTypeWithDataSet;
+
+ private static final String[] ID_PROJECTION = new String[] {BaseColumns._ID};
+ private static final Uri RAW_CONTACTS_URI_LIMIT_1 = RawContacts.CONTENT_URI.buildUpon()
+ .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, "1").build();
+
+ public static final String LOCAL_ACCOUNT_SELECTION = RawContacts.ACCOUNT_TYPE + " IS NULL AND "
+ + RawContacts.ACCOUNT_NAME + " IS NULL AND "
+ + RawContacts.DATA_SET + " IS NULL";
+
+ public AccountWithDataSet(String name, String type, String dataSet) {
+ this.name = emptyToNull(name);
+ this.type = emptyToNull(type);
+ this.dataSet = emptyToNull(dataSet);
+ mAccountTypeWithDataSet = AccountTypeWithDataSet.get(type, dataSet);
+ }
+
+ private static final String emptyToNull(String text) {
+ return TextUtils.isEmpty(text) ? null : text;
+ }
+
+ public AccountWithDataSet(Parcel in) {
+ this.name = in.readString();
+ this.type = in.readString();
+ this.dataSet = in.readString();
+ mAccountTypeWithDataSet = AccountTypeWithDataSet.get(type, dataSet);
+ }
+
+ public boolean isLocalAccount() {
+ return name == null && type == null && dataSet == null;
+ }
+
+ public static AccountWithDataSet getLocalAccount() {
+ return new AccountWithDataSet(null, null, null);
+ }
+
+ public Account getAccountOrNull() {
+ if (name != null && type != null) {
+ return new Account(name, type);
+ }
+ return null;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(name);
+ dest.writeString(type);
+ dest.writeString(dataSet);
+ }
+
+ // For Parcelable
+ public static final Creator<AccountWithDataSet> CREATOR = new Creator<AccountWithDataSet>() {
+ public AccountWithDataSet createFromParcel(Parcel source) {
+ return new AccountWithDataSet(source);
+ }
+
+ public AccountWithDataSet[] newArray(int size) {
+ return new AccountWithDataSet[size];
+ }
+ };
+
+ public AccountTypeWithDataSet getAccountTypeWithDataSet() {
+ return mAccountTypeWithDataSet;
+ }
+
+ /**
+ * Return {@code true} if this account has any contacts in the database.
+ * Touches DB. Don't use in the UI thread.
+ */
+ public boolean hasData(Context context) {
+ String selection;
+ String[] args = null;
+ if (isLocalAccount()) {
+ selection = LOCAL_ACCOUNT_SELECTION;
+ } else {
+ final String BASE_SELECTION =
+ RawContacts.ACCOUNT_TYPE + " = ?" + " AND " + RawContacts.ACCOUNT_NAME + " = ?";
+ if (TextUtils.isEmpty(dataSet)) {
+ selection = BASE_SELECTION + " AND " + RawContacts.DATA_SET + " IS NULL";
+ args = new String[] {type, name};
+ } else {
+ selection = BASE_SELECTION + " AND " + RawContacts.DATA_SET + " = ?";
+ args = new String[] {type, name, dataSet};
+ }
+ }
+
+ final Cursor c = context.getContentResolver().query(RAW_CONTACTS_URI_LIMIT_1,
+ ID_PROJECTION, selection, args, null);
+ if (c == null) return false;
+ try {
+ return c.moveToFirst();
+ } finally {
+ c.close();
+ }
+ }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof AccountWithDataSet) {
+ AccountWithDataSet other = (AccountWithDataSet) obj;
+ return Objects.equal(name, other.name)
+ && Objects.equal(type, other.type)
+ && Objects.equal(dataSet, other.dataSet);
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (name != null ? name.hashCode() : 0);
+ result = 31 * result + (type != null ? type.hashCode() : 0);
+ result = 31 * result + (dataSet != null ? dataSet.hashCode() : 0);
+ return result;
+ }
+
+ public String toString() {
+ return "AccountWithDataSet {name=" + name + ", type=" + type + ", dataSet=" + dataSet + "}";
+ }
+
+ private static StringBuilder addStringified(StringBuilder sb, AccountWithDataSet account) {
+ if (!TextUtils.isEmpty(account.name)) sb.append(account.name);
+ sb.append(STRINGIFY_SEPARATOR);
+ if (!TextUtils.isEmpty(account.type)) sb.append(account.type);
+ sb.append(STRINGIFY_SEPARATOR);
+ if (!TextUtils.isEmpty(account.dataSet)) sb.append(account.dataSet);
+
+ return sb;
+ }
+
+ /**
+ * Pack the instance into a string.
+ */
+ public String stringify() {
+ return addStringified(new StringBuilder(), this).toString();
+ }
+
+ /**
+ * Unpack a string created by {@link #stringify}.
+ *
+ * @throws IllegalArgumentException if it's an invalid string.
+ */
+ public static AccountWithDataSet unstringify(String s) {
+ final String[] array = STRINGIFY_SEPARATOR_PAT.split(s, 3);
+ if (array.length < 3) {
+ throw new IllegalArgumentException("Invalid string " + s);
+ }
+ return new AccountWithDataSet(array[0], array[1],
+ TextUtils.isEmpty(array[2]) ? null : array[2]);
+ }
+
+ /**
+ * Pack a list of {@link AccountWithDataSet} into a string.
+ */
+ public static String stringifyList(List<AccountWithDataSet> accounts) {
+ final StringBuilder sb = new StringBuilder();
+
+ for (AccountWithDataSet account : accounts) {
+ if (sb.length() > 0) {
+ sb.append(ARRAY_STRINGIFY_SEPARATOR);
+ }
+ addStringified(sb, account);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Unpack a list of {@link AccountWithDataSet} into a string.
+ *
+ * @throws IllegalArgumentException if it's an invalid string.
+ */
+ public static List<AccountWithDataSet> unstringifyList(String s) {
+ final ArrayList<AccountWithDataSet> ret = Lists.newArrayList();
+ if (TextUtils.isEmpty(s)) {
+ return ret;
+ }
+
+ final String[] array = ARRAY_STRINGIFY_SEPARATOR_PAT.split(s);
+
+ for (int i = 0; i < array.length; i++) {
+ ret.add(unstringify(array[i]));
+ }
+
+ return ret;
+ }
+}
diff --git a/src/com/android/contacts/common/model/account/BaseAccountType.java b/src/com/android/contacts/common/model/account/BaseAccountType.java
new file mode 100644
index 0000000..6481c06
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/BaseAccountType.java
@@ -0,0 +1,1488 @@
+/*
+ * 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.common.model.account;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+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.Relation;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.testing.NeededForTesting;
+import com.android.contacts.common.util.CommonDateUtils;
+import com.android.contacts.common.util.ContactDisplayUtils;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public abstract class BaseAccountType extends AccountType {
+ private static final String TAG = "BaseAccountType";
+
+ 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_EVENT = EditorInfo.TYPE_CLASS_TEXT;
+ 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;
+ protected static final int FLAGS_SIP_ADDRESS = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS; // since SIP addresses have the same
+ // basic format as email addresses
+ protected static final int FLAGS_RELATION = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
+
+ // Specify the maximum number of lines that can be used to display various field types. If no
+ // value is specified for a particular type, we use the default value from {@link DataKind}.
+ protected static final int MAX_LINES_FOR_POSTAL_ADDRESS = 10;
+ protected static final int MAX_LINES_FOR_GROUP = 10;
+ protected static final int MAX_LINES_FOR_NOTE = 100;
+
+ private interface Tag {
+ static final String DATA_KIND = "DataKind";
+ static final String TYPE = "Type";
+ }
+
+ private interface Attr {
+ static final String MAX_OCCURRENCE = "maxOccurs";
+ static final String DATE_WITH_TIME = "dateWithTime";
+ static final String YEAR_OPTIONAL = "yearOptional";
+ static final String KIND = "kind";
+ static final String TYPE = "type";
+ }
+
+ protected interface Weight {
+ static final int NONE = -1;
+ static final int PHONE = 10;
+ static final int EMAIL = 15;
+ static final int STRUCTURED_POSTAL = 25;
+ static final int NICKNAME = 111;
+ static final int EVENT = 120;
+ static final int ORGANIZATION = 125;
+ static final int NOTE = 130;
+ static final int IM = 140;
+ static final int SIP_ADDRESS = 145;
+ static final int GROUP_MEMBERSHIP = 150;
+ static final int WEBSITE = 160;
+ static final int RELATIONSHIP = 999;
+ }
+
+ public BaseAccountType() {
+ this.accountType = null;
+ this.dataSet = null;
+ this.titleRes = R.string.account_phone;
+ this.iconRes = R.mipmap.ic_contacts_launcher;
+ }
+
+ protected static EditType buildPhoneType(int type) {
+ return new EditType(type, Phone.getTypeLabelResource(type));
+ }
+
+ protected static EditType buildEmailType(int type) {
+ return new EditType(type, Email.getTypeLabelResource(type));
+ }
+
+ protected static EditType buildPostalType(int type) {
+ return new EditType(type, StructuredPostal.getTypeLabelResource(type));
+ }
+
+ protected static EditType buildImType(int type) {
+ return new EditType(type, Im.getProtocolLabelResource(type));
+ }
+
+ protected static EditType buildEventType(int type, boolean yearOptional) {
+ return new EventEditType(type, Event.getTypeResource(type)).setYearOptional(yearOptional);
+ }
+
+ protected static EditType buildRelationType(int type) {
+ return new EditType(type, Relation.getTypeLabelResource(type));
+ }
+
+ protected DataKind addDataKindStructuredName(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
+ R.string.nameLabelsGroup, Weight.NONE, true));
+ kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
+ kind.actionBody = new SimpleInflater(Nickname.NAME);
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(StructuredName.DISPLAY_NAME,
+ R.string.full_name, FLAGS_PERSON_NAME));
+ kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
+ R.string.name_phonetic_family, FLAGS_PHONETIC));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
+ R.string.name_phonetic_middle, FLAGS_PHONETIC));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
+ R.string.name_phonetic_given, FLAGS_PHONETIC));
+
+ return kind;
+ }
+
+ protected DataKind addDataKindDisplayName(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME,
+ R.string.nameLabelsGroup, Weight.NONE, true));
+ kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
+ kind.actionBody = new SimpleInflater(Nickname.NAME);
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(StructuredName.DISPLAY_NAME,
+ R.string.full_name, FLAGS_PERSON_NAME).setShortForm(true));
+
+ boolean displayOrderPrimary =
+ context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
+
+ if (!displayOrderPrimary) {
+ kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ } else {
+ kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ }
+
+ return kind;
+ }
+
+ protected DataKind addDataKindPhoneticName(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME,
+ R.string.name_phonetic, Weight.NONE, true));
+ kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
+ kind.actionBody = new SimpleInflater(Nickname.NAME);
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(DataKind.PSEUDO_COLUMN_PHONETIC_NAME,
+ R.string.name_phonetic, FLAGS_PHONETIC).setShortForm(true));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
+ R.string.name_phonetic_family, FLAGS_PHONETIC).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
+ R.string.name_phonetic_middle, FLAGS_PHONETIC).setLongForm(true));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
+ R.string.name_phonetic_given, FLAGS_PHONETIC).setLongForm(true));
+
+ return kind;
+ }
+
+ protected DataKind addDataKindNickname(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Nickname.CONTENT_ITEM_TYPE,
+ R.string.nicknameLabelsGroup, Weight.NICKNAME, true));
+ kind.typeOverallMax = 1;
+ kind.actionHeader = new SimpleInflater(R.string.nicknameLabelsGroup);
+ kind.actionBody = new SimpleInflater(Nickname.NAME);
+ 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 addDataKindPhone(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Phone.CONTENT_ITEM_TYPE, R.string.phoneLabelsGroup,
+ Weight.PHONE, true));
+ kind.iconAltRes = R.drawable.ic_message_24dp_mirrored;
+ kind.iconAltDescriptionRes = R.string.sms;
+ kind.actionHeader = new PhoneActionInflater();
+ kind.actionAltHeader = new PhoneActionAltInflater();
+ kind.actionBody = new SimpleInflater(Phone.NUMBER);
+ kind.typeColumn = Phone.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
+ 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));
+ 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 addDataKindEmail(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Email.CONTENT_ITEM_TYPE, R.string.emailLabelsGroup,
+ Weight.EMAIL, true));
+ kind.actionHeader = new EmailActionInflater();
+ kind.actionBody = new SimpleInflater(Email.DATA);
+ 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 addDataKindStructuredPostal(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(StructuredPostal.CONTENT_ITEM_TYPE,
+ R.string.postalLabelsGroup, Weight.STRUCTURED_POSTAL, true));
+ kind.actionHeader = new PostalActionInflater();
+ kind.actionBody = new SimpleInflater(StructuredPostal.FORMATTED_ADDRESS);
+ 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.FORMATTED_ADDRESS, R.string.postal_address,
+ FLAGS_POSTAL));
+
+ kind.maxLinesForDisplay = MAX_LINES_FOR_POSTAL_ADDRESS;
+
+ return kind;
+ }
+
+ protected DataKind addDataKindIm(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Im.CONTENT_ITEM_TYPE, R.string.imLabelsGroup,
+ Weight.IM, true));
+ kind.actionHeader = new ImActionInflater();
+ kind.actionBody = new SimpleInflater(Im.DATA);
+
+ // 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 addDataKindOrganization(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Organization.CONTENT_ITEM_TYPE,
+ R.string.organizationLabelsGroup, Weight.ORGANIZATION, true));
+ kind.actionHeader = new SimpleInflater(R.string.organizationLabelsGroup);
+ kind.actionBody = ORGANIZATION_BODY_INFLATER;
+ kind.typeOverallMax = 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;
+ }
+
+ protected DataKind addDataKindPhoto(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Photo.CONTENT_ITEM_TYPE, -1, Weight.NONE, true));
+ kind.typeOverallMax = 1;
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Photo.PHOTO, -1, -1));
+ return kind;
+ }
+
+ protected DataKind addDataKindNote(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Note.CONTENT_ITEM_TYPE, R.string.label_notes,
+ Weight.NOTE, true));
+ kind.typeOverallMax = 1;
+ kind.actionHeader = new SimpleInflater(R.string.label_notes);
+ kind.actionBody = new SimpleInflater(Note.NOTE);
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
+
+ kind.maxLinesForDisplay = MAX_LINES_FOR_NOTE;
+
+ return kind;
+ }
+
+ protected DataKind addDataKindWebsite(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Website.CONTENT_ITEM_TYPE,
+ R.string.websiteLabelsGroup, Weight.WEBSITE, true));
+ kind.actionHeader = new SimpleInflater(R.string.websiteLabelsGroup);
+ kind.actionBody = new SimpleInflater(Website.URL);
+ 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 addDataKindSipAddress(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(SipAddress.CONTENT_ITEM_TYPE,
+ R.string.label_sip_address, Weight.SIP_ADDRESS, true));
+
+ kind.actionHeader = new SimpleInflater(R.string.label_sip_address);
+ kind.actionBody = new SimpleInflater(SipAddress.SIP_ADDRESS);
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(SipAddress.SIP_ADDRESS,
+ R.string.label_sip_address, FLAGS_SIP_ADDRESS));
+ kind.typeOverallMax = 1;
+
+ return kind;
+ }
+
+ protected DataKind addDataKindGroupMembership(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(GroupMembership.CONTENT_ITEM_TYPE,
+ R.string.groupsLabel, Weight.GROUP_MEMBERSHIP, true));
+
+ kind.typeOverallMax = 1;
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(GroupMembership.GROUP_ROW_ID, -1, -1));
+
+ kind.maxLinesForDisplay = MAX_LINES_FOR_GROUP;
+
+ 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;
+ }
+
+ @Override
+ 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;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName()
+ + " mStringRes=" + mStringRes
+ + " mColumnName" + mColumnName;
+ }
+
+ @NeededForTesting
+ public String getColumnNameForTest() {
+ return mColumnName;
+ }
+ }
+
+ 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);
+ }
+ }
+
+ @Override
+ 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);
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName();
+ }
+ }
+
+ public static class PhoneActionInflater extends CommonInflater {
+ @Override
+ protected boolean isCustom(Integer type) {
+ return ContactDisplayUtils.isCustomPhoneType(type);
+ }
+
+ @Override
+ protected int getTypeLabelResource(Integer type) {
+ return ContactDisplayUtils.getPhoneLabelResourceId(type);
+ }
+ }
+
+ public static class PhoneActionAltInflater extends CommonInflater {
+ @Override
+ protected boolean isCustom(Integer type) {
+ return ContactDisplayUtils.isCustomPhoneType(type);
+ }
+
+ @Override
+ protected int getTypeLabelResource(Integer type) {
+ return ContactDisplayUtils.getSmsLabelResourceId(type);
+ }
+ }
+
+ 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 RelationActionInflater extends CommonInflater {
+ @Override
+ protected int getTypeLabelResource(Integer type) {
+ return Relation.getTypeLabelResource(type == null ? Relation.TYPE_CUSTOM : 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;
+ }
+ }
+ }
+
+ public static final StringInflater ORGANIZATION_BODY_INFLATER = new StringInflater() {
+ @Override
+ public CharSequence inflateUsing(Context context, ContentValues values) {
+ final CharSequence companyValue = values.containsKey(Organization.COMPANY) ?
+ values.getAsString(Organization.COMPANY) : null;
+ final CharSequence titleValue = values.containsKey(Organization.TITLE) ?
+ values.getAsString(Organization.TITLE) : null;
+
+ if (companyValue != null && titleValue != null) {
+ return companyValue + ": " + titleValue;
+ } else if (companyValue == null) {
+ return titleValue;
+ } else {
+ return companyValue;
+ }
+ }
+ };
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return false;
+ }
+
+ /**
+ * Parses the content of the EditSchema tag in contacts.xml.
+ */
+ protected final void parseEditSchema(Context context, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException, DefinitionException {
+
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ final int depth = parser.getDepth();
+ if (type != XmlPullParser.START_TAG || depth != outerDepth + 1) {
+ continue; // Not direct child tag
+ }
+
+ final String tag = parser.getName();
+
+ if (Tag.DATA_KIND.equals(tag)) {
+ for (DataKind kind : KindParser.INSTANCE.parseDataKindTag(context, parser, attrs)) {
+ addKind(kind);
+ }
+ } else {
+ Log.w(TAG, "Skipping unknown tag " + tag);
+ }
+ }
+ }
+
+ // Utility methods to keep code shorter.
+ private static boolean getAttr(AttributeSet attrs, String attribute, boolean defaultValue) {
+ return attrs.getAttributeBooleanValue(null, attribute, defaultValue);
+ }
+
+ private static int getAttr(AttributeSet attrs, String attribute, int defaultValue) {
+ return attrs.getAttributeIntValue(null, attribute, defaultValue);
+ }
+
+ private static String getAttr(AttributeSet attrs, String attribute) {
+ return attrs.getAttributeValue(null, attribute);
+ }
+
+ // TODO Extract it to its own class, and move all KindBuilders to it as well.
+ private static class KindParser {
+ public static final KindParser INSTANCE = new KindParser();
+
+ private final Map<String, KindBuilder> mBuilders = Maps.newHashMap();
+
+ private KindParser() {
+ addBuilder(new NameKindBuilder());
+ addBuilder(new NicknameKindBuilder());
+ addBuilder(new PhoneKindBuilder());
+ addBuilder(new EmailKindBuilder());
+ addBuilder(new StructuredPostalKindBuilder());
+ addBuilder(new ImKindBuilder());
+ addBuilder(new OrganizationKindBuilder());
+ addBuilder(new PhotoKindBuilder());
+ addBuilder(new NoteKindBuilder());
+ addBuilder(new WebsiteKindBuilder());
+ addBuilder(new SipAddressKindBuilder());
+ addBuilder(new GroupMembershipKindBuilder());
+ addBuilder(new EventKindBuilder());
+ addBuilder(new RelationshipKindBuilder());
+ }
+
+ private void addBuilder(KindBuilder builder) {
+ mBuilders.put(builder.getTagName(), builder);
+ }
+
+ /**
+ * Takes a {@link XmlPullParser} at the start of a DataKind tag, parses it and returns
+ * {@link DataKind}s. (Usually just one, but there are three for the "name" kind.)
+ *
+ * This method returns a list, because we need to add 3 kinds for the name data kind.
+ * (structured, display and phonetic)
+ */
+ public List<DataKind> parseDataKindTag(Context context, XmlPullParser parser,
+ AttributeSet attrs)
+ throws DefinitionException, XmlPullParserException, IOException {
+ final String kind = getAttr(attrs, Attr.KIND);
+ final KindBuilder builder = mBuilders.get(kind);
+ if (builder != null) {
+ return builder.parseDataKind(context, parser, attrs);
+ } else {
+ throw new DefinitionException("Undefined data kind '" + kind + "'");
+ }
+ }
+ }
+
+ private static abstract class KindBuilder {
+
+ public abstract String getTagName();
+
+ /**
+ * DataKind tag parser specific to each kind. Subclasses must implement it.
+ */
+ public abstract List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException, IOException;
+
+ /**
+ * Creates a new {@link DataKind}, and also parses the child Type tags in the DataKind
+ * tag.
+ */
+ protected final DataKind newDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs, boolean isPseudo, String mimeType, String typeColumn,
+ int titleRes, int weight, StringInflater actionHeader, StringInflater actionBody)
+ throws DefinitionException, XmlPullParserException, IOException {
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Adding DataKind: " + mimeType);
+ }
+
+ final DataKind kind = new DataKind(mimeType, titleRes, weight, true);
+ kind.typeColumn = typeColumn;
+ kind.actionHeader = actionHeader;
+ kind.actionBody = actionBody;
+ kind.fieldList = Lists.newArrayList();
+
+ // Get more information from the tag...
+ // A pseudo data kind doesn't have corresponding tag the XML, so we skip this.
+ if (!isPseudo) {
+ kind.typeOverallMax = getAttr(attrs, Attr.MAX_OCCURRENCE, -1);
+
+ // Process "Type" tags.
+ // If a kind has the type column, contacts.xml must have at least one type
+ // definition. Otherwise, it mustn't have a type definition.
+ if (kind.typeColumn != null) {
+ // Parse and add types.
+ kind.typeList = Lists.newArrayList();
+ parseTypes(context, parser, attrs, kind, true);
+ if (kind.typeList.size() == 0) {
+ throw new DefinitionException(
+ "Kind " + kind.mimeType + " must have at least one type");
+ }
+ } else {
+ // Make sure it has no types.
+ parseTypes(context, parser, attrs, kind, false /* can't have types */);
+ }
+ }
+
+ return kind;
+ }
+
+ /**
+ * Parses Type elements in a DataKind element, and if {@code canHaveTypes} is true adds
+ * them to the given {@link DataKind}. Otherwise the {@link DataKind} can't have a type,
+ * so throws {@link DefinitionException}.
+ */
+ private void parseTypes(Context context, XmlPullParser parser, AttributeSet attrs,
+ DataKind kind, boolean canHaveTypes)
+ throws DefinitionException, XmlPullParserException, IOException {
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ final int depth = parser.getDepth();
+ if (type != XmlPullParser.START_TAG || depth != outerDepth + 1) {
+ continue; // Not direct child tag
+ }
+
+ final String tag = parser.getName();
+ if (Tag.TYPE.equals(tag)) {
+ if (canHaveTypes) {
+ kind.typeList.add(parseTypeTag(parser, attrs, kind));
+ } else {
+ throw new DefinitionException(
+ "Kind " + kind.mimeType + " can't have types");
+ }
+ } else {
+ throw new DefinitionException("Unknown tag: " + tag);
+ }
+ }
+ }
+
+ /**
+ * Parses a single Type element and returns an {@link EditType} built from it. Uses
+ * {@link #buildEditTypeForTypeTag} defined in subclasses to actually build an
+ * {@link EditType}.
+ */
+ private EditType parseTypeTag(XmlPullParser parser, AttributeSet attrs, DataKind kind)
+ throws DefinitionException {
+
+ final String typeName = getAttr(attrs, Attr.TYPE);
+
+ final EditType et = buildEditTypeForTypeTag(attrs, typeName);
+ if (et == null) {
+ throw new DefinitionException(
+ "Undefined type '" + typeName + "' for data kind '" + kind.mimeType + "'");
+ }
+ et.specificMax = getAttr(attrs, Attr.MAX_OCCURRENCE, -1);
+
+ return et;
+ }
+
+ /**
+ * Returns an {@link EditType} for the given "type". Subclasses may optionally use
+ * the attributes in the tag to set optional values.
+ * (e.g. "yearOptional" for the event kind)
+ */
+ protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
+ return null;
+ }
+
+ protected final void throwIfList(DataKind kind) throws DefinitionException {
+ if (kind.typeOverallMax != 1) {
+ throw new DefinitionException(
+ "Kind " + kind.mimeType + " must have 'overallMax=\"1\"'");
+ }
+ }
+ }
+
+ /**
+ * DataKind parser for Name. (structured, display, phonetic)
+ */
+ private static class NameKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "name";
+ }
+
+ private static void checkAttributeTrue(boolean value, String attrName)
+ throws DefinitionException {
+ if (!value) {
+ throw new DefinitionException(attrName + " must be true");
+ }
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+
+ // Build 3 data kinds:
+ // - StructuredName.CONTENT_ITEM_TYPE
+ // - DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME
+ // - DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME
+
+ final boolean displayOrderPrimary =
+ context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
+
+ final boolean supportsDisplayName = getAttr(attrs, "supportsDisplayName", false);
+ final boolean supportsPrefix = getAttr(attrs, "supportsPrefix", false);
+ final boolean supportsMiddleName = getAttr(attrs, "supportsMiddleName", false);
+ final boolean supportsSuffix = getAttr(attrs, "supportsSuffix", false);
+ final boolean supportsPhoneticFamilyName =
+ getAttr(attrs, "supportsPhoneticFamilyName", false);
+ final boolean supportsPhoneticMiddleName =
+ getAttr(attrs, "supportsPhoneticMiddleName", false);
+ final boolean supportsPhoneticGivenName =
+ getAttr(attrs, "supportsPhoneticGivenName", false);
+
+ // For now, every things must be supported.
+ checkAttributeTrue(supportsDisplayName, "supportsDisplayName");
+ checkAttributeTrue(supportsPrefix, "supportsPrefix");
+ checkAttributeTrue(supportsMiddleName, "supportsMiddleName");
+ checkAttributeTrue(supportsSuffix, "supportsSuffix");
+ checkAttributeTrue(supportsPhoneticFamilyName, "supportsPhoneticFamilyName");
+ checkAttributeTrue(supportsPhoneticMiddleName, "supportsPhoneticMiddleName");
+ checkAttributeTrue(supportsPhoneticGivenName, "supportsPhoneticGivenName");
+
+ final List<DataKind> kinds = Lists.newArrayList();
+
+ // Structured name
+ final DataKind ks = newDataKind(context, parser, attrs, false,
+ StructuredName.CONTENT_ITEM_TYPE, null, R.string.nameLabelsGroup, Weight.NONE,
+ new SimpleInflater(R.string.nameLabelsGroup),
+ new SimpleInflater(Nickname.NAME));
+
+ throwIfList(ks);
+ kinds.add(ks);
+
+ // Note about setLongForm/setShortForm below.
+ // We need to set this only when the type supports display name. (=supportsDisplayName)
+ // Otherwise (i.e. Exchange) we don't set these flags, but instead make some fields
+ // "optional".
+
+ ks.fieldList.add(new EditField(StructuredName.DISPLAY_NAME, R.string.full_name,
+ FLAGS_PERSON_NAME));
+ ks.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ ks.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ ks.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ ks.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ ks.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ ks.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
+ R.string.name_phonetic_family, FLAGS_PHONETIC));
+ ks.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
+ R.string.name_phonetic_middle, FLAGS_PHONETIC));
+ ks.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
+ R.string.name_phonetic_given, FLAGS_PHONETIC));
+
+ // Display name
+ final DataKind kd = newDataKind(context, parser, attrs, true,
+ DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME, null,
+ R.string.nameLabelsGroup, Weight.NONE,
+ new SimpleInflater(R.string.nameLabelsGroup),
+ new SimpleInflater(Nickname.NAME));
+ kd.typeOverallMax = 1;
+ kinds.add(kd);
+
+ kd.fieldList.add(new EditField(StructuredName.DISPLAY_NAME,
+ R.string.full_name, FLAGS_PERSON_NAME).setShortForm(true));
+
+ if (!displayOrderPrimary) {
+ kd.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kd.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kd.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kd.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kd.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ } else {
+ kd.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kd.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kd.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kd.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ kd.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
+ FLAGS_PERSON_NAME).setLongForm(true));
+ }
+
+ // Phonetic name
+ final DataKind kp = newDataKind(context, parser, attrs, true,
+ DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME, null,
+ R.string.name_phonetic, Weight.NONE,
+ new SimpleInflater(R.string.nameLabelsGroup),
+ new SimpleInflater(Nickname.NAME));
+ kp.typeOverallMax = 1;
+ kinds.add(kp);
+
+ // We may want to change the order depending on displayOrderPrimary too.
+ kp.fieldList.add(new EditField(DataKind.PSEUDO_COLUMN_PHONETIC_NAME,
+ R.string.name_phonetic, FLAGS_PHONETIC).setShortForm(true));
+ kp.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
+ R.string.name_phonetic_family, FLAGS_PHONETIC).setLongForm(true));
+ kp.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
+ R.string.name_phonetic_middle, FLAGS_PHONETIC).setLongForm(true));
+ kp.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
+ R.string.name_phonetic_given, FLAGS_PHONETIC).setLongForm(true));
+ return kinds;
+ }
+ }
+
+ private static class NicknameKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "nickname";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ Nickname.CONTENT_ITEM_TYPE, null, R.string.nicknameLabelsGroup, Weight.NICKNAME,
+ new SimpleInflater(R.string.nicknameLabelsGroup),
+ new SimpleInflater(Nickname.NAME));
+
+ kind.fieldList.add(new EditField(Nickname.NAME, R.string.nicknameLabelsGroup,
+ FLAGS_PERSON_NAME));
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Nickname.TYPE, Nickname.TYPE_DEFAULT);
+
+ throwIfList(kind);
+ return Lists.newArrayList(kind);
+ }
+ }
+
+ private static class PhoneKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "phone";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ Phone.CONTENT_ITEM_TYPE, Phone.TYPE, R.string.phoneLabelsGroup, Weight.PHONE,
+ new PhoneActionInflater(), new SimpleInflater(Phone.NUMBER));
+
+ kind.iconAltRes = R.drawable.ic_message_24dp_mirrored;
+ kind.iconAltDescriptionRes = R.string.sms;
+ kind.actionAltHeader = new PhoneActionAltInflater();
+
+ kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
+
+ return Lists.newArrayList(kind);
+ }
+
+ /** Just to avoid line-wrapping... */
+ protected static EditType build(int type, boolean secondary) {
+ return new EditType(type, Phone.getTypeLabelResource(type)).setSecondary(secondary);
+ }
+
+ @Override
+ protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
+ if ("home".equals(type)) return build(Phone.TYPE_HOME, false);
+ if ("mobile".equals(type)) return build(Phone.TYPE_MOBILE, false);
+ if ("work".equals(type)) return build(Phone.TYPE_WORK, false);
+ if ("fax_work".equals(type)) return build(Phone.TYPE_FAX_WORK, true);
+ if ("fax_home".equals(type)) return build(Phone.TYPE_FAX_HOME, true);
+ if ("pager".equals(type)) return build(Phone.TYPE_PAGER, true);
+ if ("other".equals(type)) return build(Phone.TYPE_OTHER, false);
+ if ("callback".equals(type)) return build(Phone.TYPE_CALLBACK, true);
+ if ("car".equals(type)) return build(Phone.TYPE_CAR, true);
+ if ("company_main".equals(type)) return build(Phone.TYPE_COMPANY_MAIN, true);
+ if ("isdn".equals(type)) return build(Phone.TYPE_ISDN, true);
+ if ("main".equals(type)) return build(Phone.TYPE_MAIN, true);
+ if ("other_fax".equals(type)) return build(Phone.TYPE_OTHER_FAX, true);
+ if ("radio".equals(type)) return build(Phone.TYPE_RADIO, true);
+ if ("telex".equals(type)) return build(Phone.TYPE_TELEX, true);
+ if ("tty_tdd".equals(type)) return build(Phone.TYPE_TTY_TDD, true);
+ if ("work_mobile".equals(type)) return build(Phone.TYPE_WORK_MOBILE, true);
+ if ("work_pager".equals(type)) return build(Phone.TYPE_WORK_PAGER, true);
+
+ // Note "assistant" used to be a custom column for the fallback type, but not anymore.
+ if ("assistant".equals(type)) return build(Phone.TYPE_ASSISTANT, true);
+ if ("mms".equals(type)) return build(Phone.TYPE_MMS, true);
+ if ("custom".equals(type)) {
+ return build(Phone.TYPE_CUSTOM, true).setCustomColumn(Phone.LABEL);
+ }
+ return null;
+ }
+ }
+
+ private static class EmailKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "email";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ Email.CONTENT_ITEM_TYPE, Email.TYPE, R.string.emailLabelsGroup, Weight.EMAIL,
+ new EmailActionInflater(), new SimpleInflater(Email.DATA));
+ kind.fieldList.add(new EditField(Email.DATA, R.string.emailLabelsGroup, FLAGS_EMAIL));
+
+ return Lists.newArrayList(kind);
+ }
+
+ @Override
+ protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
+ // EditType is mutable, so we need to create a new instance every time.
+ if ("home".equals(type)) return buildEmailType(Email.TYPE_HOME);
+ if ("work".equals(type)) return buildEmailType(Email.TYPE_WORK);
+ if ("other".equals(type)) return buildEmailType(Email.TYPE_OTHER);
+ if ("mobile".equals(type)) return buildEmailType(Email.TYPE_MOBILE);
+ if ("custom".equals(type)) {
+ return buildEmailType(Email.TYPE_CUSTOM)
+ .setSecondary(true).setCustomColumn(Email.LABEL);
+ }
+ return null;
+ }
+ }
+
+ private static class StructuredPostalKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "postal";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE,
+ R.string.postalLabelsGroup, Weight.STRUCTURED_POSTAL,
+ new PostalActionInflater(),
+ new SimpleInflater(StructuredPostal.FORMATTED_ADDRESS));
+
+ if (getAttr(attrs, "needsStructured", false)) {
+ if (Locale.JAPANESE.getLanguage().equals(Locale.getDefault().getLanguage())) {
+ // Japanese order
+ kind.fieldList.add(new EditField(StructuredPostal.COUNTRY,
+ R.string.postal_country, FLAGS_POSTAL).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredPostal.POSTCODE,
+ R.string.postal_postcode, FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.REGION,
+ R.string.postal_region, FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.CITY,
+ R.string.postal_city,FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.STREET,
+ R.string.postal_street, FLAGS_POSTAL));
+ } else {
+ // Generic order
+ 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));
+ }
+ } else {
+ kind.maxLinesForDisplay= MAX_LINES_FOR_POSTAL_ADDRESS;
+ kind.fieldList.add(
+ new EditField(StructuredPostal.FORMATTED_ADDRESS, R.string.postal_address,
+ FLAGS_POSTAL));
+ }
+
+ return Lists.newArrayList(kind);
+ }
+
+ @Override
+ protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
+ // EditType is mutable, so we need to create a new instance every time.
+ if ("home".equals(type)) return buildPostalType(StructuredPostal.TYPE_HOME);
+ if ("work".equals(type)) return buildPostalType(StructuredPostal.TYPE_WORK);
+ if ("other".equals(type)) return buildPostalType(StructuredPostal.TYPE_OTHER);
+ if ("custom".equals(type)) {
+ return buildPostalType(StructuredPostal.TYPE_CUSTOM)
+ .setSecondary(true).setCustomColumn(Email.LABEL);
+ }
+ return null;
+ }
+ }
+
+ private static class ImKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "im";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+
+ // IM is special:
+ // - It uses "protocol" as the custom label field
+ // - Its TYPE is fixed to TYPE_OTHER
+
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ Im.CONTENT_ITEM_TYPE, Im.PROTOCOL, R.string.imLabelsGroup, Weight.IM,
+ new ImActionInflater(), new SimpleInflater(Im.DATA) // header / action
+ );
+ kind.fieldList.add(new EditField(Im.DATA, R.string.imLabelsGroup, FLAGS_EMAIL));
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Im.TYPE, Im.TYPE_OTHER);
+
+ return Lists.newArrayList(kind);
+ }
+
+ @Override
+ protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
+ if ("aim".equals(type)) return buildImType(Im.PROTOCOL_AIM);
+ if ("msn".equals(type)) return buildImType(Im.PROTOCOL_MSN);
+ if ("yahoo".equals(type)) return buildImType(Im.PROTOCOL_YAHOO);
+ if ("skype".equals(type)) return buildImType(Im.PROTOCOL_SKYPE);
+ if ("qq".equals(type)) return buildImType(Im.PROTOCOL_QQ);
+ if ("google_talk".equals(type)) return buildImType(Im.PROTOCOL_GOOGLE_TALK);
+ if ("icq".equals(type)) return buildImType(Im.PROTOCOL_ICQ);
+ if ("jabber".equals(type)) return buildImType(Im.PROTOCOL_JABBER);
+ if ("custom".equals(type)) {
+ return buildImType(Im.PROTOCOL_CUSTOM).setSecondary(true)
+ .setCustomColumn(Im.CUSTOM_PROTOCOL);
+ }
+ return null;
+ }
+ }
+
+ private static class OrganizationKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "organization";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ Organization.CONTENT_ITEM_TYPE, null, R.string.organizationLabelsGroup,
+ Weight.ORGANIZATION,
+ new SimpleInflater(R.string.organizationLabelsGroup),
+ ORGANIZATION_BODY_INFLATER);
+
+ 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));
+
+ throwIfList(kind);
+
+ return Lists.newArrayList(kind);
+ }
+ }
+
+ private static class PhotoKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "photo";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ Photo.CONTENT_ITEM_TYPE, null /* no type */, Weight.NONE, -1,
+ null, null // no header, no body
+ );
+
+ kind.fieldList.add(new EditField(Photo.PHOTO, -1, -1));
+
+ throwIfList(kind);
+
+ return Lists.newArrayList(kind);
+ }
+ }
+
+ private static class NoteKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "note";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ Note.CONTENT_ITEM_TYPE, null, R.string.label_notes, Weight.NOTE,
+ new SimpleInflater(R.string.label_notes), new SimpleInflater(Note.NOTE));
+
+ kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
+ kind.maxLinesForDisplay = MAX_LINES_FOR_NOTE;
+
+ throwIfList(kind);
+
+ return Lists.newArrayList(kind);
+ }
+ }
+
+ private static class WebsiteKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "website";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ Website.CONTENT_ITEM_TYPE, null, R.string.websiteLabelsGroup, Weight.WEBSITE,
+ new SimpleInflater(R.string.websiteLabelsGroup),
+ new SimpleInflater(Website.URL));
+
+ kind.fieldList.add(new EditField(Website.URL, R.string.websiteLabelsGroup,
+ FLAGS_WEBSITE));
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Website.TYPE, Website.TYPE_OTHER);
+
+ return Lists.newArrayList(kind);
+ }
+ }
+
+ private static class SipAddressKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "sip_address";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ SipAddress.CONTENT_ITEM_TYPE, null, R.string.label_sip_address,
+ Weight.SIP_ADDRESS,
+ new SimpleInflater(R.string.label_sip_address),
+ new SimpleInflater(SipAddress.SIP_ADDRESS));
+
+ kind.fieldList.add(new EditField(SipAddress.SIP_ADDRESS,
+ R.string.label_sip_address, FLAGS_SIP_ADDRESS));
+
+ throwIfList(kind);
+
+ return Lists.newArrayList(kind);
+ }
+ }
+
+ private static class GroupMembershipKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "group_membership";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ GroupMembership.CONTENT_ITEM_TYPE, null,
+ R.string.groupsLabel, Weight.GROUP_MEMBERSHIP, null, null);
+
+ kind.fieldList.add(new EditField(GroupMembership.GROUP_ROW_ID, -1, -1));
+ kind.maxLinesForDisplay = MAX_LINES_FOR_GROUP;
+
+ throwIfList(kind);
+
+ return Lists.newArrayList(kind);
+ }
+ }
+
+ /**
+ * Event DataKind parser.
+ *
+ * Event DataKind is used only for Google/Exchange types, so this parser is not used for now.
+ */
+ private static class EventKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "event";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ Event.CONTENT_ITEM_TYPE, Event.TYPE, R.string.eventLabelsGroup, Weight.EVENT,
+ new EventActionInflater(), new SimpleInflater(Event.START_DATE));
+
+ kind.fieldList.add(new EditField(Event.DATA, R.string.eventLabelsGroup, FLAGS_EVENT));
+
+ if (getAttr(attrs, Attr.DATE_WITH_TIME, false)) {
+ kind.dateFormatWithoutYear = CommonDateUtils.NO_YEAR_DATE_AND_TIME_FORMAT;
+ kind.dateFormatWithYear = CommonDateUtils.DATE_AND_TIME_FORMAT;
+ } else {
+ kind.dateFormatWithoutYear = CommonDateUtils.NO_YEAR_DATE_FORMAT;
+ kind.dateFormatWithYear = CommonDateUtils.FULL_DATE_FORMAT;
+ }
+
+ return Lists.newArrayList(kind);
+ }
+
+ @Override
+ protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
+ final boolean yo = getAttr(attrs, Attr.YEAR_OPTIONAL, false);
+
+ if ("birthday".equals(type)) {
+ return buildEventType(Event.TYPE_BIRTHDAY, yo).setSpecificMax(1);
+ }
+ if ("anniversary".equals(type)) return buildEventType(Event.TYPE_ANNIVERSARY, yo);
+ if ("other".equals(type)) return buildEventType(Event.TYPE_OTHER, yo);
+ if ("custom".equals(type)) {
+ return buildEventType(Event.TYPE_CUSTOM, yo)
+ .setSecondary(true).setCustomColumn(Event.LABEL);
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Relationship DataKind parser.
+ *
+ * Relationship DataKind is used only for Google/Exchange types, so this parser is not used for
+ * now.
+ */
+ private static class RelationshipKindBuilder extends KindBuilder {
+ @Override
+ public String getTagName() {
+ return "relationship";
+ }
+
+ @Override
+ public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
+ AttributeSet attrs) throws DefinitionException, XmlPullParserException,
+ IOException {
+ final DataKind kind = newDataKind(context, parser, attrs, false,
+ Relation.CONTENT_ITEM_TYPE, Relation.TYPE,
+ R.string.relationLabelsGroup, Weight.RELATIONSHIP,
+ new RelationActionInflater(), new SimpleInflater(Relation.NAME));
+
+ kind.fieldList.add(new EditField(Relation.DATA, R.string.relationLabelsGroup,
+ FLAGS_RELATION));
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Relation.TYPE, Relation.TYPE_SPOUSE);
+
+ return Lists.newArrayList(kind);
+ }
+
+ @Override
+ protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
+ // EditType is mutable, so we need to create a new instance every time.
+ if ("assistant".equals(type)) return buildRelationType(Relation.TYPE_ASSISTANT);
+ if ("brother".equals(type)) return buildRelationType(Relation.TYPE_BROTHER);
+ if ("child".equals(type)) return buildRelationType(Relation.TYPE_CHILD);
+ if ("domestic_partner".equals(type)) {
+ return buildRelationType(Relation.TYPE_DOMESTIC_PARTNER);
+ }
+ if ("father".equals(type)) return buildRelationType(Relation.TYPE_FATHER);
+ if ("friend".equals(type)) return buildRelationType(Relation.TYPE_FRIEND);
+ if ("manager".equals(type)) return buildRelationType(Relation.TYPE_MANAGER);
+ if ("mother".equals(type)) return buildRelationType(Relation.TYPE_MOTHER);
+ if ("parent".equals(type)) return buildRelationType(Relation.TYPE_PARENT);
+ if ("partner".equals(type)) return buildRelationType(Relation.TYPE_PARTNER);
+ if ("referred_by".equals(type)) return buildRelationType(Relation.TYPE_REFERRED_BY);
+ if ("relative".equals(type)) return buildRelationType(Relation.TYPE_RELATIVE);
+ if ("sister".equals(type)) return buildRelationType(Relation.TYPE_SISTER);
+ if ("spouse".equals(type)) return buildRelationType(Relation.TYPE_SPOUSE);
+ if ("custom".equals(type)) {
+ return buildRelationType(Relation.TYPE_CUSTOM).setSecondary(true)
+ .setCustomColumn(Relation.LABEL);
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/model/account/ExchangeAccountType.java b/src/com/android/contacts/common/model/account/ExchangeAccountType.java
new file mode 100644
index 0000000..7020836
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/ExchangeAccountType.java
@@ -0,0 +1,349 @@
+/*
+ * 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.common.model.account;
+
+import android.content.ContentValues;
+import android.content.Context;
+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.util.Log;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.util.CommonDateUtils;
+import com.google.common.collect.Lists;
+
+import java.util.Locale;
+
+public class ExchangeAccountType extends BaseAccountType {
+ private static final String TAG = "ExchangeAccountType";
+
+ private static final String ACCOUNT_TYPE_AOSP = "com.android.exchange";
+ private static final String ACCOUNT_TYPE_GOOGLE_1 = "com.google.android.exchange";
+ private static final String ACCOUNT_TYPE_GOOGLE_2 = "com.google.android.gm.exchange";
+
+ public ExchangeAccountType(Context context, String authenticatorPackageName, String type) {
+ this.accountType = type;
+ this.resourcePackageName = null;
+ this.syncAdapterPackageName = authenticatorPackageName;
+
+ try {
+ addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhoneticName(context);
+ addDataKindNickname(context);
+ addDataKindPhone(context);
+ addDataKindEmail(context);
+ addDataKindStructuredPostal(context);
+ addDataKindIm(context);
+ addDataKindOrganization(context);
+ addDataKindPhoto(context);
+ addDataKindNote(context);
+ addDataKindEvent(context);
+ addDataKindWebsite(context);
+ addDataKindGroupMembership(context);
+
+ mIsInitialized = true;
+ } catch (DefinitionException e) {
+ Log.e(TAG, "Problem building account type", e);
+ }
+ }
+
+ public static boolean isExchangeType(String type) {
+ return ACCOUNT_TYPE_AOSP.equals(type) || ACCOUNT_TYPE_GOOGLE_1.equals(type)
+ || ACCOUNT_TYPE_GOOGLE_2.equals(type);
+ }
+
+ @Override
+ protected DataKind addDataKindStructuredName(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
+ R.string.nameLabelsGroup, Weight.NONE, true));
+ kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
+ kind.actionBody = new SimpleInflater(Nickname.NAME);
+
+ 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.FAMILY_NAME,
+ R.string.name_family, FLAGS_PERSON_NAME));
+ kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME,
+ R.string.name_middle, FLAGS_PERSON_NAME));
+ kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME,
+ R.string.name_given, FLAGS_PERSON_NAME));
+ kind.fieldList.add(new EditField(StructuredName.SUFFIX,
+ R.string.name_suffix, FLAGS_PERSON_NAME));
+
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
+ R.string.name_phonetic_family, FLAGS_PHONETIC));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
+ R.string.name_phonetic_given, FLAGS_PHONETIC));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindDisplayName(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME,
+ R.string.nameLabelsGroup, Weight.NONE, true));
+
+ boolean displayOrderPrimary =
+ context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
+ FLAGS_PERSON_NAME).setOptional(true));
+ if (!displayOrderPrimary) {
+ kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME,
+ R.string.name_family, 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.GIVEN_NAME,
+ R.string.name_given, FLAGS_PERSON_NAME));
+ } else {
+ 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));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindPhoneticName(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME,
+ R.string.name_phonetic, Weight.NONE, true));
+ kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
+ kind.actionBody = new SimpleInflater(Nickname.NAME);
+
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
+ R.string.name_phonetic_family, FLAGS_PHONETIC));
+ kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
+ R.string.name_phonetic_given, FLAGS_PHONETIC));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindNickname(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindNickname(context);
+
+ 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 addDataKindPhone(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindPhone(context);
+
+ kind.typeColumn = Phone.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE).setSpecificMax(1));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_HOME).setSpecificMax(2));
+ 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));
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindEmail(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindEmail(context);
+
+ kind.typeOverallMax = 3;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Email.DATA, R.string.emailLabelsGroup, FLAGS_EMAIL));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindStructuredPostal(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindStructuredPostal(context);
+
+ final boolean useJapaneseOrder =
+ Locale.JAPANESE.getLanguage().equals(Locale.getDefault().getLanguage());
+ 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();
+ if (useJapaneseOrder) {
+ kind.fieldList.add(new EditField(StructuredPostal.COUNTRY,
+ R.string.postal_country, FLAGS_POSTAL).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredPostal.POSTCODE,
+ R.string.postal_postcode, FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.REGION,
+ R.string.postal_region, FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.CITY,
+ R.string.postal_city,FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.STREET,
+ R.string.postal_street, FLAGS_POSTAL));
+ } else {
+ 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 addDataKindIm(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindIm(context);
+
+ // Types are not supported for IM. There can be 3 IMs, but OWA only shows only the first
+ kind.typeOverallMax = 3;
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Im.TYPE, Im.TYPE_OTHER);
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Im.DATA, R.string.imLabelsGroup, FLAGS_EMAIL));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindOrganization(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindOrganization(context);
+
+ kind.typeOverallMax = 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 addDataKindPhoto(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindPhoto(context);
+
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Photo.PHOTO, -1, -1));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindNote(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindNote(context);
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
+
+ return kind;
+ }
+
+ protected DataKind addDataKindEvent(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Event.CONTENT_ITEM_TYPE, R.string.eventLabelsGroup,
+ Weight.EVENT, true));
+ kind.actionHeader = new EventActionInflater();
+ kind.actionBody = new SimpleInflater(Event.START_DATE);
+
+ kind.typeOverallMax = 1;
+
+ kind.typeColumn = Event.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildEventType(Event.TYPE_BIRTHDAY, false).setSpecificMax(1));
+
+ kind.dateFormatWithYear = CommonDateUtils.DATE_AND_TIME_FORMAT;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Event.DATA, R.string.eventLabelsGroup, FLAGS_EVENT));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindWebsite(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindWebsite(context);
+
+ kind.typeOverallMax = 1;
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Website.URL, R.string.websiteLabelsGroup, FLAGS_WEBSITE));
+
+ return kind;
+ }
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return true;
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return true;
+ }
+}
diff --git a/src/com/android/contacts/common/model/account/ExternalAccountType.java b/src/com/android/contacts/common/model/account/ExternalAccountType.java
new file mode 100644
index 0000000..1298fb3
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/ExternalAccountType.java
@@ -0,0 +1,441 @@
+/*
+ * 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.common.model.account;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.google.common.annotations.VisibleForTesting;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A general contacts account type descriptor.
+ */
+public class ExternalAccountType extends BaseAccountType {
+ private static final String TAG = "ExternalAccountType";
+
+ private static final String SYNC_META_DATA = "android.content.SyncAdapter";
+
+ /**
+ * The metadata name for so-called "contacts.xml".
+ *
+ * On LMP and later, we also accept the "alternate" name.
+ * This is to allow sync adapters to have a contacts.xml without making it visible on older
+ * platforms. If you modify this also update the corresponding list in
+ * ContactsProvider/PhotoPriorityResolver
+ */
+ private static final String[] METADATA_CONTACTS_NAMES = new String[] {
+ "android.provider.ALTERNATE_CONTACTS_STRUCTURE",
+ "android.provider.CONTACTS_STRUCTURE"
+ };
+
+ private static final String TAG_CONTACTS_SOURCE_LEGACY = "ContactsSource";
+ private static final String TAG_CONTACTS_ACCOUNT_TYPE = "ContactsAccountType";
+ private static final String TAG_CONTACTS_DATA_KIND = "ContactsDataKind";
+ private static final String TAG_EDIT_SCHEMA = "EditSchema";
+
+ private static final String ATTR_EDIT_CONTACT_ACTIVITY = "editContactActivity";
+ private static final String ATTR_CREATE_CONTACT_ACTIVITY = "createContactActivity";
+ private static final String ATTR_INVITE_CONTACT_ACTIVITY = "inviteContactActivity";
+ private static final String ATTR_INVITE_CONTACT_ACTION_LABEL = "inviteContactActionLabel";
+ private static final String ATTR_VIEW_CONTACT_NOTIFY_SERVICE = "viewContactNotifyService";
+ private static final String ATTR_VIEW_GROUP_ACTIVITY = "viewGroupActivity";
+ private static final String ATTR_VIEW_GROUP_ACTION_LABEL = "viewGroupActionLabel";
+ private static final String ATTR_DATA_SET = "dataSet";
+ private static final String ATTR_EXTENSION_PACKAGE_NAMES = "extensionPackageNames";
+
+ // The following attributes should only be set in non-sync-adapter account types. They allow
+ // for the account type and resource IDs to be specified without an associated authenticator.
+ private static final String ATTR_ACCOUNT_TYPE = "accountType";
+ private static final String ATTR_ACCOUNT_LABEL = "accountTypeLabel";
+ private static final String ATTR_ACCOUNT_ICON = "accountTypeIcon";
+
+ private final boolean mIsExtension;
+
+ private String mEditContactActivityClassName;
+ private String mCreateContactActivityClassName;
+ private String mInviteContactActivity;
+ private String mInviteActionLabelAttribute;
+ private int mInviteActionLabelResId;
+ private String mViewContactNotifyService;
+ private String mViewGroupActivity;
+ private String mViewGroupLabelAttribute;
+ private int mViewGroupLabelResId;
+ private List<String> mExtensionPackageNames;
+ private String mAccountTypeLabelAttribute;
+ private String mAccountTypeIconAttribute;
+ private boolean mHasContactsMetadata;
+ private boolean mHasEditSchema;
+
+ public ExternalAccountType(Context context, String resPackageName, boolean isExtension) {
+ this(context, resPackageName, isExtension, null);
+ }
+
+ /**
+ * Constructor used for testing to initialize with any arbitrary XML.
+ *
+ * @param injectedMetadata If non-null, it'll be used to initialize the type. Only set by
+ * tests. If null, the metadata is loaded from the specified package.
+ */
+ ExternalAccountType(Context context, String packageName, boolean isExtension,
+ XmlResourceParser injectedMetadata) {
+ this.mIsExtension = isExtension;
+ this.resourcePackageName = packageName;
+ this.syncAdapterPackageName = packageName;
+
+ final XmlResourceParser parser;
+ if (injectedMetadata == null) {
+ parser = loadContactsXml(context, packageName);
+ } else {
+ parser = injectedMetadata;
+ }
+ boolean needLineNumberInErrorLog = true;
+ try {
+ if (parser != null) {
+ inflate(context, parser);
+ }
+
+ // Done parsing; line number no longer needed in error log.
+ needLineNumberInErrorLog = false;
+ if (mHasEditSchema) {
+ checkKindExists(StructuredName.CONTENT_ITEM_TYPE);
+ checkKindExists(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME);
+ checkKindExists(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME);
+ checkKindExists(Photo.CONTENT_ITEM_TYPE);
+ } else {
+ // Bring in name and photo from fallback source, which are non-optional
+ addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhoneticName(context);
+ addDataKindPhoto(context);
+ }
+ } catch (DefinitionException e) {
+ final StringBuilder error = new StringBuilder();
+ error.append("Problem reading XML");
+ if (needLineNumberInErrorLog && (parser != null)) {
+ error.append(" in line ");
+ error.append(parser.getLineNumber());
+ }
+ error.append(" for external package ");
+ error.append(packageName);
+
+ Log.e(TAG, error.toString(), e);
+ return;
+ } finally {
+ if (parser != null) {
+ parser.close();
+ }
+ }
+
+ mExtensionPackageNames = new ArrayList<String>();
+ mInviteActionLabelResId = resolveExternalResId(context, mInviteActionLabelAttribute,
+ syncAdapterPackageName, ATTR_INVITE_CONTACT_ACTION_LABEL);
+ mViewGroupLabelResId = resolveExternalResId(context, mViewGroupLabelAttribute,
+ syncAdapterPackageName, ATTR_VIEW_GROUP_ACTION_LABEL);
+ titleRes = resolveExternalResId(context, mAccountTypeLabelAttribute,
+ syncAdapterPackageName, ATTR_ACCOUNT_LABEL);
+ iconRes = resolveExternalResId(context, mAccountTypeIconAttribute,
+ syncAdapterPackageName, ATTR_ACCOUNT_ICON);
+
+ // If we reach this point, the account type has been successfully initialized.
+ mIsInitialized = true;
+ }
+
+ /**
+ * Returns the CONTACTS_STRUCTURE metadata (aka "contacts.xml") in the given apk package.
+ *
+ * This method looks through all services in the package that handle sync adapter
+ * intents for the first one that contains CONTACTS_STRUCTURE metadata. We have to look
+ * through all sync adapters in the package in case there are contacts and other sync
+ * adapters (eg, calendar) in the same package.
+ *
+ * Returns {@code null} if the package has no CONTACTS_STRUCTURE metadata. In this case
+ * the account type *will* be initialized with minimal configuration.
+ */
+ public static XmlResourceParser loadContactsXml(Context context, String resPackageName) {
+ final PackageManager pm = context.getPackageManager();
+ final Intent intent = new Intent(SYNC_META_DATA).setPackage(resPackageName);
+ final List<ResolveInfo> intentServices = pm.queryIntentServices(intent,
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+
+ if (intentServices != null) {
+ for (final ResolveInfo resolveInfo : intentServices) {
+ final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ if (serviceInfo == null) {
+ continue;
+ }
+ for (String metadataName : METADATA_CONTACTS_NAMES) {
+ final XmlResourceParser parser = serviceInfo.loadXmlMetaData(
+ pm, metadataName);
+ if (parser != null) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, String.format("Metadata loaded from: %s, %s, %s",
+ serviceInfo.packageName, serviceInfo.name,
+ metadataName));
+ }
+ return parser;
+ }
+ }
+ }
+ }
+
+ // Package was found, but that doesn't contain the CONTACTS_STRUCTURE metadata.
+ return null;
+ }
+
+ /**
+ * Returns {@code TRUE} if the package contains CONTACTS_STRUCTURE metadata.
+ */
+ public static boolean hasContactsXml(Context context, String resPackageName) {
+ return loadContactsXml(context, resPackageName) != null;
+ }
+
+ private void checkKindExists(String mimeType) throws DefinitionException {
+ if (getKindForMimetype(mimeType) == null) {
+ throw new DefinitionException(mimeType + " must be supported");
+ }
+ }
+
+ @Override
+ public boolean isEmbedded() {
+ return false;
+ }
+
+ @Override
+ public boolean isExtension() {
+ return mIsExtension;
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return mHasEditSchema;
+ }
+
+ /**
+ * Whether this account type has the android.provider.CONTACTS_STRUCTURE metadata xml.
+ */
+ public boolean hasContactsMetadata() {
+ return mHasContactsMetadata;
+ }
+
+ @Override
+ public String getEditContactActivityClassName() {
+ return mEditContactActivityClassName;
+ }
+
+ @Override
+ public String getCreateContactActivityClassName() {
+ return mCreateContactActivityClassName;
+ }
+
+ @Override
+ public String getInviteContactActivityClassName() {
+ return mInviteContactActivity;
+ }
+
+ @Override
+ protected int getInviteContactActionResId() {
+ return mInviteActionLabelResId;
+ }
+
+ @Override
+ public String getViewContactNotifyServiceClassName() {
+ return mViewContactNotifyService;
+ }
+
+ @Override
+ public String getViewGroupActivity() {
+ return mViewGroupActivity;
+ }
+
+ @Override
+ protected int getViewGroupLabelResId() {
+ return mViewGroupLabelResId;
+ }
+
+ @Override
+ public List<String> getExtensionPackageNames() {
+ return mExtensionPackageNames;
+ }
+
+ /**
+ * Inflate this {@link AccountType} from the given parser. This may only
+ * load details matching the publicly-defined schema.
+ */
+ protected void inflate(Context context, XmlPullParser parser) throws DefinitionException {
+ 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");
+ }
+
+ String rootTag = parser.getName();
+ if (!TAG_CONTACTS_ACCOUNT_TYPE.equals(rootTag) &&
+ !TAG_CONTACTS_SOURCE_LEGACY.equals(rootTag)) {
+ throw new IllegalStateException("Top level element must be "
+ + TAG_CONTACTS_ACCOUNT_TYPE + ", not " + rootTag);
+ }
+
+ mHasContactsMetadata = true;
+
+ int attributeCount = parser.getAttributeCount();
+ for (int i = 0; i < attributeCount; i++) {
+ String attr = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, attr + "=" + value);
+ }
+ if (ATTR_EDIT_CONTACT_ACTIVITY.equals(attr)) {
+ mEditContactActivityClassName = value;
+ } else if (ATTR_CREATE_CONTACT_ACTIVITY.equals(attr)) {
+ mCreateContactActivityClassName = value;
+ } else if (ATTR_INVITE_CONTACT_ACTIVITY.equals(attr)) {
+ mInviteContactActivity = value;
+ } else if (ATTR_INVITE_CONTACT_ACTION_LABEL.equals(attr)) {
+ mInviteActionLabelAttribute = value;
+ } else if (ATTR_VIEW_CONTACT_NOTIFY_SERVICE.equals(attr)) {
+ mViewContactNotifyService = value;
+ } else if (ATTR_VIEW_GROUP_ACTIVITY.equals(attr)) {
+ mViewGroupActivity = value;
+ } else if (ATTR_VIEW_GROUP_ACTION_LABEL.equals(attr)) {
+ mViewGroupLabelAttribute = value;
+ } else if (ATTR_DATA_SET.equals(attr)) {
+ dataSet = value;
+ } else if (ATTR_EXTENSION_PACKAGE_NAMES.equals(attr)) {
+ mExtensionPackageNames.add(value);
+ } else if (ATTR_ACCOUNT_TYPE.equals(attr)) {
+ accountType = value;
+ } else if (ATTR_ACCOUNT_LABEL.equals(attr)) {
+ mAccountTypeLabelAttribute = value;
+ } else if (ATTR_ACCOUNT_ICON.equals(attr)) {
+ mAccountTypeIconAttribute = value;
+ } else {
+ Log.e(TAG, "Unsupported attribute " + attr);
+ }
+ }
+
+ // Parse all children kinds
+ final int startDepth = parser.getDepth();
+ while (((type = parser.next()) != XmlPullParser.END_TAG
+ || parser.getDepth() > startDepth)
+ && type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG || parser.getDepth() != startDepth + 1) {
+ continue; // Not a direct child tag
+ }
+
+ String tag = parser.getName();
+ if (TAG_EDIT_SCHEMA.equals(tag)) {
+ mHasEditSchema = true;
+ parseEditSchema(context, parser, attrs);
+ } else if (TAG_CONTACTS_DATA_KIND.equals(tag)) {
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.ContactsDataKind);
+ final DataKind kind = new DataKind();
+
+ kind.mimeType = a
+ .getString(R.styleable.ContactsDataKind_android_mimeType);
+ final String summaryColumn = a.getString(
+ R.styleable.ContactsDataKind_android_summaryColumn);
+ if (summaryColumn != null) {
+ // Inflate a specific column as summary when requested
+ kind.actionHeader = new SimpleInflater(summaryColumn);
+ }
+ final String detailColumn = a.getString(
+ R.styleable.ContactsDataKind_android_detailColumn);
+ if (detailColumn != null) {
+ // Inflate specific column as summary
+ kind.actionBody = new SimpleInflater(detailColumn);
+ }
+
+ a.recycle();
+
+ addKind(kind);
+ }
+ }
+ } catch (XmlPullParserException e) {
+ throw new DefinitionException("Problem reading XML", e);
+ } catch (IOException e) {
+ throw new DefinitionException("Problem reading XML", e);
+ }
+ }
+
+ /**
+ * Takes a string in the "@xxx/yyy" format and return the resource ID for the resource in
+ * the resource package.
+ *
+ * If the argument is in the invalid format or isn't a resource name, it returns -1.
+ *
+ * @param context context
+ * @param resourceName Resource name in the "@xxx/yyy" format, e.g. "@string/invite_lavbel"
+ * @param packageName name of the package containing the resource.
+ * @param xmlAttributeName attribute name which the resource came from. Used for logging.
+ */
+ @VisibleForTesting
+ static int resolveExternalResId(Context context, String resourceName,
+ String packageName, String xmlAttributeName) {
+ if (TextUtils.isEmpty(resourceName)) {
+ return -1; // Empty text is okay.
+ }
+ if (resourceName.charAt(0) != '@') {
+ Log.e(TAG, xmlAttributeName + " must be a resource name beginnig with '@'");
+ return -1;
+ }
+ final String name = resourceName.substring(1);
+ final Resources res;
+ try {
+ res = context.getPackageManager().getResourcesForApplication(packageName);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Unable to load package " + packageName);
+ return -1;
+ }
+ final int resId = res.getIdentifier(name, null, packageName);
+ if (resId == 0) {
+ Log.e(TAG, "Unable to load " + resourceName + " from package " + packageName);
+ return -1;
+ }
+ return resId;
+ }
+}
diff --git a/src/com/android/contacts/common/model/account/FallbackAccountType.java b/src/com/android/contacts/common/model/account/FallbackAccountType.java
new file mode 100644
index 0000000..42e6b6a
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/FallbackAccountType.java
@@ -0,0 +1,79 @@
+/*
+ * 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.common.model.account;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.testing.NeededForTesting;
+
+public class FallbackAccountType extends BaseAccountType {
+ private static final String TAG = "FallbackAccountType";
+
+ private FallbackAccountType(Context context, String resPackageName) {
+ this.accountType = null;
+ this.dataSet = null;
+ this.titleRes = R.string.account_phone;
+ this.iconRes = R.drawable.ic_device;
+
+ // Note those are only set for unit tests.
+ this.resourcePackageName = resPackageName;
+ this.syncAdapterPackageName = resPackageName;
+
+ try {
+ addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhoneticName(context);
+ addDataKindNickname(context);
+ addDataKindPhone(context);
+ addDataKindEmail(context);
+ addDataKindStructuredPostal(context);
+ addDataKindIm(context);
+ addDataKindOrganization(context);
+ addDataKindPhoto(context);
+ addDataKindNote(context);
+ addDataKindWebsite(context);
+ addDataKindSipAddress(context);
+ addDataKindGroupMembership(context);
+
+ mIsInitialized = true;
+ } catch (DefinitionException e) {
+ Log.e(TAG, "Problem building account type", e);
+ }
+ }
+
+ public FallbackAccountType(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Used to compare with an {@link ExternalAccountType} built from a test contacts.xml.
+ * In order to build {@link DataKind}s with the same resource package name,
+ * {@code resPackageName} is injectable.
+ */
+ @NeededForTesting
+ static AccountType createWithPackageNameForTest(Context context, String resPackageName) {
+ return new FallbackAccountType(context, resPackageName);
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return true;
+ }
+}
diff --git a/src/com/android/contacts/common/model/account/GoogleAccountType.java b/src/com/android/contacts/common/model/account/GoogleAccountType.java
new file mode 100644
index 0000000..8f7f172
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/GoogleAccountType.java
@@ -0,0 +1,204 @@
+/*
+ * 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.common.model.account;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Relation;
+import android.util.Log;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.util.CommonDateUtils;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+public class GoogleAccountType extends BaseAccountType {
+ private static final String TAG = "GoogleAccountType";
+
+ /**
+ * The package name that we should load contacts.xml from and rely on to handle
+ * G+ account actions. Even though this points to gms, in some cases gms will still hand
+ * off responsibility to the G+ app.
+ */
+ public static final String PLUS_EXTENSION_PACKAGE_NAME = "com.google.android.gms";
+
+ public static final String ACCOUNT_TYPE = "com.google";
+
+ private static final List<String> mExtensionPackages =
+ Lists.newArrayList(PLUS_EXTENSION_PACKAGE_NAME);
+
+ public GoogleAccountType(Context context, String authenticatorPackageName) {
+ this.accountType = ACCOUNT_TYPE;
+ this.resourcePackageName = null;
+ this.syncAdapterPackageName = authenticatorPackageName;
+
+ try {
+ addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhoneticName(context);
+ addDataKindNickname(context);
+ addDataKindPhone(context);
+ addDataKindEmail(context);
+ addDataKindStructuredPostal(context);
+ addDataKindIm(context);
+ addDataKindOrganization(context);
+ addDataKindPhoto(context);
+ addDataKindNote(context);
+ addDataKindWebsite(context);
+ addDataKindSipAddress(context);
+ addDataKindGroupMembership(context);
+ addDataKindRelation(context);
+ addDataKindEvent(context);
+
+ mIsInitialized = true;
+ } catch (DefinitionException e) {
+ Log.e(TAG, "Problem building account type", e);
+ }
+ }
+
+ @Override
+ public List<String> getExtensionPackageNames() {
+ return mExtensionPackages;
+ }
+
+ @Override
+ protected DataKind addDataKindPhone(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindPhone(context);
+
+ kind.typeColumn = Phone.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_WORK));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MAIN));
+ 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 addDataKindEmail(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindEmail(context);
+
+ 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;
+ }
+
+ private DataKind addDataKindRelation(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Relation.CONTENT_ITEM_TYPE,
+ R.string.relationLabelsGroup, Weight.RELATIONSHIP, true));
+ kind.actionHeader = new RelationActionInflater();
+ kind.actionBody = new SimpleInflater(Relation.NAME);
+
+ kind.typeColumn = Relation.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildRelationType(Relation.TYPE_ASSISTANT));
+ kind.typeList.add(buildRelationType(Relation.TYPE_BROTHER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_CHILD));
+ kind.typeList.add(buildRelationType(Relation.TYPE_DOMESTIC_PARTNER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_FATHER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_FRIEND));
+ kind.typeList.add(buildRelationType(Relation.TYPE_MANAGER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_MOTHER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_PARENT));
+ kind.typeList.add(buildRelationType(Relation.TYPE_PARTNER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_REFERRED_BY));
+ kind.typeList.add(buildRelationType(Relation.TYPE_RELATIVE));
+ kind.typeList.add(buildRelationType(Relation.TYPE_SISTER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_SPOUSE));
+ kind.typeList.add(buildRelationType(Relation.TYPE_CUSTOM).setSecondary(true)
+ .setCustomColumn(Relation.LABEL));
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Relation.TYPE, Relation.TYPE_SPOUSE);
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Relation.DATA, R.string.relationLabelsGroup,
+ FLAGS_RELATION));
+
+ return kind;
+ }
+
+ private DataKind addDataKindEvent(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Event.CONTENT_ITEM_TYPE,
+ R.string.eventLabelsGroup, Weight.EVENT, true));
+ kind.actionHeader = new EventActionInflater();
+ kind.actionBody = new SimpleInflater(Event.START_DATE);
+
+ kind.typeColumn = Event.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.dateFormatWithoutYear = CommonDateUtils.NO_YEAR_DATE_FORMAT;
+ kind.dateFormatWithYear = CommonDateUtils.FULL_DATE_FORMAT;
+ kind.typeList.add(buildEventType(Event.TYPE_BIRTHDAY, true).setSpecificMax(1));
+ kind.typeList.add(buildEventType(Event.TYPE_ANNIVERSARY, false));
+ kind.typeList.add(buildEventType(Event.TYPE_OTHER, false));
+ kind.typeList.add(buildEventType(Event.TYPE_CUSTOM, false).setSecondary(true)
+ .setCustomColumn(Event.LABEL));
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Event.DATA, R.string.eventLabelsGroup, FLAGS_EVENT));
+
+ return kind;
+ }
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return true;
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return true;
+ }
+
+ @Override
+ public String getViewContactNotifyServiceClassName() {
+ return "com.google.android.syncadapters.contacts." +
+ "SyncHighResPhotoIntentService";
+ }
+
+ @Override
+ public String getViewContactNotifyServicePackageName() {
+ return "com.google.android.syncadapters.contacts";
+ }
+}
diff --git a/src/com/android/contacts/common/model/account/SamsungAccountType.java b/src/com/android/contacts/common/model/account/SamsungAccountType.java
new file mode 100644
index 0000000..85a9ab8
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/SamsungAccountType.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2015 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.common.model.account;
+
+import com.google.common.collect.Lists;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.util.CommonDateUtils;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Relation;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.util.Log;
+
+import java.util.Locale;
+
+/**
+ * A writable account type that can be used to support samsung contacts. This may not perfectly
+ * match Samsung's latest intended account schema.
+ *
+ * This is only used to partially support Samsung accounts. The DataKind labels & fields are
+ * setup to support the values used by Samsung. But, not everything in the Samsung account type is
+ * supported. The Samsung account type includes a "Message Type" mimetype that we have no intention
+ * of showing inside the Contact editor. Similarly, we don't handle the "Ringtone" mimetype here
+ * since managing ringtones is handled in a different flow.
+ */
+public class SamsungAccountType extends BaseAccountType {
+ private static final String TAG = "KnownExternalAccountType";
+ private static final String ACCOUNT_TYPE_SAMSUNG = "com.osp.app.signin";
+
+ public SamsungAccountType(Context context, String authenticatorPackageName, String type) {
+ this.accountType = type;
+ this.resourcePackageName = null;
+ this.syncAdapterPackageName = authenticatorPackageName;
+
+ try {
+ addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhoneticName(context);
+ addDataKindNickname(context);
+ addDataKindPhone(context);
+ addDataKindEmail(context);
+ addDataKindStructuredPostal(context);
+ addDataKindIm(context);
+ addDataKindOrganization(context);
+ addDataKindPhoto(context);
+ addDataKindNote(context);
+ addDataKindWebsite(context);
+ addDataKindGroupMembership(context);
+ addDataKindRelation(context);
+ addDataKindEvent(context);
+
+ mIsInitialized = true;
+ } catch (DefinitionException e) {
+ Log.e(TAG, "Problem building account type", e);
+ }
+ }
+
+ /**
+ * Returns {@code TRUE} if this is samsung's account type and Samsung hasn't bothered to
+ * define a contacts.xml to provide a more accurate definition than ours.
+ */
+ public static boolean isSamsungAccountType(Context context, String type,
+ String packageName) {
+ return ACCOUNT_TYPE_SAMSUNG.equals(type)
+ && !ExternalAccountType.hasContactsXml(context, packageName);
+ }
+
+ @Override
+ protected DataKind addDataKindStructuredPostal(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindStructuredPostal(context);
+
+ final boolean useJapaneseOrder =
+ Locale.JAPANESE.getLanguage().equals(Locale.getDefault().getLanguage());
+ 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();
+ if (useJapaneseOrder) {
+ kind.fieldList.add(new EditField(StructuredPostal.COUNTRY,
+ R.string.postal_country, FLAGS_POSTAL).setOptional(true));
+ kind.fieldList.add(new EditField(StructuredPostal.POSTCODE,
+ R.string.postal_postcode, FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.REGION,
+ R.string.postal_region, FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.CITY,
+ R.string.postal_city,FLAGS_POSTAL));
+ kind.fieldList.add(new EditField(StructuredPostal.STREET,
+ R.string.postal_street, FLAGS_POSTAL));
+ } else {
+ 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 addDataKindPhone(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindPhone(context);
+
+ kind.typeColumn = Phone.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_WORK));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MAIN));
+ 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_RADIO).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 addDataKindEmail(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindEmail(context);
+
+ 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;
+ }
+
+ private DataKind addDataKindRelation(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Relation.CONTENT_ITEM_TYPE,
+ R.string.relationLabelsGroup, 160, true));
+ kind.actionHeader = new RelationActionInflater();
+ kind.actionBody = new SimpleInflater(Relation.NAME);
+
+ kind.typeColumn = Relation.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildRelationType(Relation.TYPE_ASSISTANT));
+ kind.typeList.add(buildRelationType(Relation.TYPE_BROTHER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_CHILD));
+ kind.typeList.add(buildRelationType(Relation.TYPE_DOMESTIC_PARTNER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_FATHER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_FRIEND));
+ kind.typeList.add(buildRelationType(Relation.TYPE_MANAGER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_MOTHER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_PARENT));
+ kind.typeList.add(buildRelationType(Relation.TYPE_PARTNER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_REFERRED_BY));
+ kind.typeList.add(buildRelationType(Relation.TYPE_RELATIVE));
+ kind.typeList.add(buildRelationType(Relation.TYPE_SISTER));
+ kind.typeList.add(buildRelationType(Relation.TYPE_SPOUSE));
+ kind.typeList.add(buildRelationType(Relation.TYPE_CUSTOM).setSecondary(true)
+ .setCustomColumn(Relation.LABEL));
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Relation.TYPE, Relation.TYPE_SPOUSE);
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Relation.DATA, R.string.relationLabelsGroup,
+ FLAGS_RELATION));
+
+ return kind;
+ }
+
+ private DataKind addDataKindEvent(Context context) throws DefinitionException {
+ DataKind kind = addKind(new DataKind(Event.CONTENT_ITEM_TYPE,
+ R.string.eventLabelsGroup, 150, true));
+ kind.actionHeader = new EventActionInflater();
+ kind.actionBody = new SimpleInflater(Event.START_DATE);
+
+ kind.typeColumn = Event.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.dateFormatWithoutYear = CommonDateUtils.NO_YEAR_DATE_FORMAT;
+ kind.dateFormatWithYear = CommonDateUtils.FULL_DATE_FORMAT;
+ kind.typeList.add(buildEventType(Event.TYPE_BIRTHDAY, true).setSpecificMax(1));
+ kind.typeList.add(buildEventType(Event.TYPE_ANNIVERSARY, false));
+ kind.typeList.add(buildEventType(Event.TYPE_OTHER, false));
+ kind.typeList.add(buildEventType(Event.TYPE_CUSTOM, false).setSecondary(true)
+ .setCustomColumn(Event.LABEL));
+
+ kind.defaultValues = new ContentValues();
+ kind.defaultValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
+
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Event.DATA, R.string.eventLabelsGroup, FLAGS_EVENT));
+
+ return kind;
+ }
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return true;
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return true;
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/DataItem.java b/src/com/android/contacts/common/model/dataitem/DataItem.java
new file mode 100644
index 0000000..4e66e32
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/DataItem.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.provider.ContactsContract.CommonDataKinds.Identity;
+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.Relation;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.provider.ContactsContract.Contacts.Data;
+import android.provider.ContactsContract.Contacts.Entity;
+
+import com.android.contacts.common.Collapser;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.model.RawContactModifier;
+
+/**
+ * This is the base class for data items, which represents a row from the Data table.
+ */
+public class DataItem implements Collapser.Collapsible<DataItem> {
+
+ private final ContentValues mContentValues;
+ protected DataKind mKind;
+
+ protected DataItem(ContentValues values) {
+ mContentValues = values;
+ }
+
+ /**
+ * Factory for creating subclasses of DataItem objects based on the mimetype in the
+ * content values. Raw contact is the raw contact that this data item is associated with.
+ */
+ public static DataItem createFrom(ContentValues values) {
+ final String mimeType = values.getAsString(Data.MIMETYPE);
+ if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new GroupMembershipDataItem(values);
+ } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new StructuredNameDataItem(values);
+ } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new PhoneDataItem(values);
+ } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new EmailDataItem(values);
+ } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new StructuredPostalDataItem(values);
+ } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new ImDataItem(values);
+ } else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new OrganizationDataItem(values);
+ } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new NicknameDataItem(values);
+ } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new NoteDataItem(values);
+ } else if (Website.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new WebsiteDataItem(values);
+ } else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new SipAddressDataItem(values);
+ } else if (Event.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new EventDataItem(values);
+ } else if (Relation.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new RelationDataItem(values);
+ } else if (Identity.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new IdentityDataItem(values);
+ } else if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new PhotoDataItem(values);
+ }
+
+ // generic
+ return new DataItem(values);
+ }
+
+ public ContentValues getContentValues() {
+ return mContentValues;
+ }
+
+ public void setRawContactId(long rawContactId) {
+ mContentValues.put(Data.RAW_CONTACT_ID, rawContactId);
+ }
+
+ public Long getRawContactId() {
+ return mContentValues.getAsLong(Data.RAW_CONTACT_ID);
+ }
+
+ /**
+ * Returns the data id.
+ */
+ public long getId() {
+ return mContentValues.getAsLong(Data._ID);
+ }
+
+ /**
+ * Returns the mimetype of the data.
+ */
+ public String getMimeType() {
+ return mContentValues.getAsString(Data.MIMETYPE);
+ }
+
+ public void setMimeType(String mimeType) {
+ mContentValues.put(Data.MIMETYPE, mimeType);
+ }
+
+ public boolean isPrimary() {
+ Integer primary = mContentValues.getAsInteger(Data.IS_PRIMARY);
+ return primary != null && primary != 0;
+ }
+
+ public boolean isSuperPrimary() {
+ Integer superPrimary = mContentValues.getAsInteger(Data.IS_SUPER_PRIMARY);
+ return superPrimary != null && superPrimary != 0;
+ }
+
+ public boolean hasKindTypeColumn(DataKind kind) {
+ final String key = kind.typeColumn;
+ return key != null && mContentValues.containsKey(key) &&
+ mContentValues.getAsInteger(key) != null;
+ }
+
+ public int getKindTypeColumn(DataKind kind) {
+ final String key = kind.typeColumn;
+ return mContentValues.getAsInteger(key);
+ }
+
+ /**
+ * Indicates the carrier presence value for the current {@link DataItem}.
+ *
+ * @return {@link Data#CARRIER_PRESENCE_VT_CAPABLE} if the {@link DataItem} supports carrier
+ * video calling, {@code 0} otherwise.
+ */
+ public int getCarrierPresence() {
+ final Integer value = mContentValues.getAsInteger(Data.CARRIER_PRESENCE);
+ return value != null ? value.intValue() : 0;
+ }
+
+ /**
+ * This builds the data string depending on the type of data item by using the generic
+ * DataKind object underneath.
+ */
+ public String buildDataString(Context context, DataKind kind) {
+ if (kind.actionBody == null) {
+ return null;
+ }
+ CharSequence actionBody = kind.actionBody.inflateUsing(context, mContentValues);
+ return actionBody == null ? null : actionBody.toString();
+ }
+
+ /**
+ * This builds the data string(intended for display) depending on the type of data item. It
+ * returns the same value as {@link #buildDataString} by default, but certain data items can
+ * override it to provide their version of formatted data strings.
+ *
+ * @return Data string representing the data item, possibly formatted for display
+ */
+ public String buildDataStringForDisplay(Context context, DataKind kind) {
+ return buildDataString(context, kind);
+ }
+
+ public void setDataKind(DataKind kind) {
+ mKind = kind;
+ }
+
+ public DataKind getDataKind() {
+ return mKind;
+ }
+
+ public Integer getTimesUsed() {
+ return mContentValues.getAsInteger(Entity.TIMES_USED);
+ }
+
+ public Long getLastTimeUsed() {
+ return mContentValues.getAsLong(Entity.LAST_TIME_USED);
+ }
+
+ @Override
+ public void collapseWith(DataItem that) {
+ DataKind thisKind = getDataKind();
+ DataKind thatKind = that.getDataKind();
+ // If this does not have a type and that does, or if that's type is higher precedence,
+ // use that's type
+ if ((!hasKindTypeColumn(thisKind) && that.hasKindTypeColumn(thatKind)) ||
+ that.hasKindTypeColumn(thatKind) &&
+ RawContactModifier.getTypePrecedence(thisKind, getKindTypeColumn(thisKind))
+ >
+ RawContactModifier.getTypePrecedence(thatKind, that.getKindTypeColumn(thatKind))) {
+ mContentValues.put(thatKind.typeColumn, that.getKindTypeColumn(thatKind));
+ mKind = thatKind;
+ }
+
+ // Choose the max of the maxLines and maxLabelLines values.
+ mKind.maxLinesForDisplay = Math.max(thisKind.maxLinesForDisplay,
+ thatKind.maxLinesForDisplay);
+
+ // If any of the collapsed entries are super primary make the whole thing super primary.
+ if (isSuperPrimary() || that.isSuperPrimary()) {
+ mContentValues.put(Data.IS_SUPER_PRIMARY, 1);
+ mContentValues.put(Data.IS_PRIMARY, 1);
+ }
+
+ // If any of the collapsed entries are primary make the whole thing primary.
+ if (isPrimary() || that.isPrimary()) {
+ mContentValues.put(Data.IS_PRIMARY, 1);
+ }
+
+ // Add up the times used
+ mContentValues.put(Entity.TIMES_USED, (getTimesUsed() == null ? 0 : getTimesUsed()) +
+ (that.getTimesUsed() == null ? 0 : that.getTimesUsed()));
+
+ // Use the most recent time
+ mContentValues.put(Entity.LAST_TIME_USED,
+ Math.max(getLastTimeUsed() == null ? 0 : getLastTimeUsed(),
+ that.getLastTimeUsed() == null ? 0 : that.getLastTimeUsed()));
+ }
+
+ @Override
+ public boolean shouldCollapseWith(DataItem t, Context context) {
+ if (mKind == null || t.getDataKind() == null) {
+ return false;
+ }
+ return MoreContactUtils.shouldCollapse(getMimeType(), buildDataString(context, mKind),
+ t.getMimeType(), t.buildDataString(context, t.getDataKind()));
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/DataKind.java b/src/com/android/contacts/common/model/dataitem/DataKind.java
new file mode 100644
index 0000000..e4b6aea
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/DataKind.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract.Data;
+
+import com.android.contacts.common.model.account.AccountType.EditField;
+import com.android.contacts.common.model.account.AccountType.EditType;
+import com.android.contacts.common.model.account.AccountType.StringInflater;
+import com.google.common.collect.Iterators;
+
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+/**
+ * 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 final class DataKind {
+
+ public static final String PSEUDO_MIME_TYPE_DISPLAY_NAME = "#displayName";
+ public static final String PSEUDO_MIME_TYPE_PHONETIC_NAME = "#phoneticName";
+ public static final String PSEUDO_COLUMN_PHONETIC_NAME = "#phoneticName";
+
+ public String resourcePackageName;
+ public String mimeType;
+ public int titleRes;
+ public int iconAltRes;
+ public int iconAltDescriptionRes;
+ public int weight;
+ public boolean editable;
+
+ public StringInflater actionHeader;
+ public StringInflater actionAltHeader;
+ public StringInflater actionBody;
+
+ public String typeColumn;
+
+ /**
+ * Maximum number of values allowed in the list. -1 represents infinity.
+ */
+ public int typeOverallMax;
+
+ public List<EditType> typeList;
+ public List<EditField> fieldList;
+
+ public ContentValues defaultValues;
+
+ /**
+ * If this is a date field, this specifies the format of the date when saving. The
+ * date includes year, month and day. If this is not a date field or the date field is not
+ * editable, this value should be ignored.
+ */
+ public SimpleDateFormat dateFormatWithoutYear;
+
+ /**
+ * If this is a date field, this specifies the format of the date when saving. The
+ * date includes month and day. If this is not a date field, the field is not editable or
+ * dates without year are not supported, this value should be ignored.
+ */
+ public SimpleDateFormat dateFormatWithYear;
+
+ /**
+ * The number of lines available for displaying this kind of data.
+ * Defaults to 1.
+ */
+ public int maxLinesForDisplay;
+
+ public DataKind() {
+ maxLinesForDisplay = 1;
+ }
+
+ public DataKind(String mimeType, int titleRes, int weight, boolean editable) {
+ this.mimeType = mimeType;
+ this.titleRes = titleRes;
+ this.weight = weight;
+ this.editable = editable;
+ this.typeOverallMax = -1;
+ maxLinesForDisplay = 1;
+ }
+
+ public String getKindString(Context context) {
+ return (titleRes == -1 || titleRes == 0) ? "" : context.getString(titleRes);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("DataKind:");
+ sb.append(" resPackageName=").append(resourcePackageName);
+ sb.append(" mimeType=").append(mimeType);
+ sb.append(" titleRes=").append(titleRes);
+ sb.append(" iconAltRes=").append(iconAltRes);
+ sb.append(" iconAltDescriptionRes=").append(iconAltDescriptionRes);
+ sb.append(" weight=").append(weight);
+ sb.append(" editable=").append(editable);
+ sb.append(" actionHeader=").append(actionHeader);
+ sb.append(" actionAltHeader=").append(actionAltHeader);
+ sb.append(" actionBody=").append(actionBody);
+ sb.append(" typeColumn=").append(typeColumn);
+ sb.append(" typeOverallMax=").append(typeOverallMax);
+ sb.append(" typeList=").append(toString(typeList));
+ sb.append(" fieldList=").append(toString(fieldList));
+ sb.append(" defaultValues=").append(defaultValues);
+ sb.append(" dateFormatWithoutYear=").append(toString(dateFormatWithoutYear));
+ sb.append(" dateFormatWithYear=").append(toString(dateFormatWithYear));
+
+ return sb.toString();
+ }
+
+ public static String toString(SimpleDateFormat format) {
+ return format == null ? "(null)" : format.toPattern();
+ }
+
+ public static String toString(Iterable<?> list) {
+ if (list == null) {
+ return "(null)";
+ } else {
+ return Iterators.toString(list.iterator());
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/EmailDataItem.java b/src/com/android/contacts/common/model/dataitem/EmailDataItem.java
new file mode 100644
index 0000000..23efb01
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/EmailDataItem.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+
+/**
+ * Represents an email data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Email}.
+ */
+public class EmailDataItem extends DataItem {
+
+ /* package */ EmailDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getAddress() {
+ return getContentValues().getAsString(Email.ADDRESS);
+ }
+
+ public String getDisplayName() {
+ return getContentValues().getAsString(Email.DISPLAY_NAME);
+ }
+
+ public String getData() {
+ return getContentValues().getAsString(Email.DATA);
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(Email.LABEL);
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/EventDataItem.java b/src/com/android/contacts/common/model/dataitem/EventDataItem.java
new file mode 100644
index 0000000..5096fea
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/EventDataItem.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.text.TextUtils;
+
+/**
+ * Represents an event data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Event}.
+ */
+public class EventDataItem extends DataItem {
+
+ /* package */ EventDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getStartDate() {
+ return getContentValues().getAsString(Event.START_DATE);
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(Event.LABEL);
+ }
+
+ @Override
+ public boolean shouldCollapseWith(DataItem t, Context context) {
+ if (!(t instanceof EventDataItem) || mKind == null || t.getDataKind() == null) {
+ return false;
+ }
+ final EventDataItem that = (EventDataItem) t;
+ // Events can be different (anniversary, birthday) but have the same start date
+ if (!TextUtils.equals(getStartDate(), that.getStartDate())) {
+ return false;
+ } else if (!hasKindTypeColumn(mKind) || !that.hasKindTypeColumn(that.getDataKind())) {
+ return hasKindTypeColumn(mKind) == that.hasKindTypeColumn(that.getDataKind());
+ } else if (getKindTypeColumn(mKind) != that.getKindTypeColumn(that.getDataKind())) {
+ return false;
+ } else if (getKindTypeColumn(mKind) == Event.TYPE_CUSTOM &&
+ !TextUtils.equals(getLabel(), that.getLabel())) {
+ // Check if custom types are not the same
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/GroupMembershipDataItem.java b/src/com/android/contacts/common/model/dataitem/GroupMembershipDataItem.java
new file mode 100644
index 0000000..41f19e6
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/GroupMembershipDataItem.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+
+/**
+ * Represents a group memebership data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.GroupMembership}.
+ */
+public class GroupMembershipDataItem extends DataItem {
+
+ /* package */ GroupMembershipDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public Long getGroupRowId() {
+ return getContentValues().getAsLong(GroupMembership.GROUP_ROW_ID);
+ }
+
+ public String getGroupSourceId() {
+ return getContentValues().getAsString(GroupMembership.GROUP_SOURCE_ID);
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/IdentityDataItem.java b/src/com/android/contacts/common/model/dataitem/IdentityDataItem.java
new file mode 100644
index 0000000..29e9a40
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/IdentityDataItem.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Identity;
+
+/**
+ * Represents an identity data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Identity}.
+ */
+public class IdentityDataItem extends DataItem {
+
+ /* package */ IdentityDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getIdentity() {
+ return getContentValues().getAsString(Identity.IDENTITY);
+ }
+
+ public String getNamespace() {
+ return getContentValues().getAsString(Identity.NAMESPACE);
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/ImDataItem.java b/src/com/android/contacts/common/model/dataitem/ImDataItem.java
new file mode 100644
index 0000000..f89e5c6
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/ImDataItem.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.text.TextUtils;
+
+/**
+ * Represents an IM data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Im}.
+ */
+public class ImDataItem extends DataItem {
+
+ private final boolean mCreatedFromEmail;
+
+ /* package */ ImDataItem(ContentValues values) {
+ super(values);
+ mCreatedFromEmail = false;
+ }
+
+ private ImDataItem(ContentValues values, boolean createdFromEmail) {
+ super(values);
+ mCreatedFromEmail = createdFromEmail;
+ }
+
+ public static ImDataItem createFromEmail(EmailDataItem item) {
+ final ImDataItem im = new ImDataItem(new ContentValues(item.getContentValues()), true);
+ im.setMimeType(Im.CONTENT_ITEM_TYPE);
+ return im;
+ }
+
+ public String getData() {
+ if (mCreatedFromEmail) {
+ return getContentValues().getAsString(Email.DATA);
+ } else {
+ return getContentValues().getAsString(Im.DATA);
+ }
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(Im.LABEL);
+ }
+
+ /**
+ * Values are one of Im.PROTOCOL_
+ */
+ public Integer getProtocol() {
+ return getContentValues().getAsInteger(Im.PROTOCOL);
+ }
+
+ public boolean isProtocolValid() {
+ return getProtocol() != null;
+ }
+
+ public String getCustomProtocol() {
+ return getContentValues().getAsString(Im.CUSTOM_PROTOCOL);
+ }
+
+ public int getChatCapability() {
+ Integer result = getContentValues().getAsInteger(Im.CHAT_CAPABILITY);
+ return result == null ? 0 : result;
+ }
+
+ public boolean isCreatedFromEmail() {
+ return mCreatedFromEmail;
+ }
+
+ @Override
+ public boolean shouldCollapseWith(DataItem t, Context context) {
+ if (!(t instanceof ImDataItem) || mKind == null || t.getDataKind() == null) {
+ return false;
+ }
+ final ImDataItem that = (ImDataItem) t;
+ // IM can have the same data put different protocol. These should not collapse.
+ if (!getData().equals(that.getData())) {
+ return false;
+ } else if (!isProtocolValid() || !that.isProtocolValid()) {
+ // Deal with invalid protocol as if it was custom. If either has a non valid
+ // protocol, check to see if the other has a valid that is not custom
+ if (isProtocolValid()) {
+ return getProtocol() == Im.PROTOCOL_CUSTOM;
+ } else if (that.isProtocolValid()) {
+ return that.getProtocol() == Im.PROTOCOL_CUSTOM;
+ }
+ return true;
+ } else if (getProtocol() != that.getProtocol()) {
+ return false;
+ } else if (getProtocol() == Im.PROTOCOL_CUSTOM &&
+ !TextUtils.equals(getCustomProtocol(), that.getCustomProtocol())) {
+ // Check if custom protocols are not the same
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/NicknameDataItem.java b/src/com/android/contacts/common/model/dataitem/NicknameDataItem.java
new file mode 100644
index 0000000..e7f9d4a
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/NicknameDataItem.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+
+/**
+ * Represents a nickname data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Nickname}.
+ */
+public class NicknameDataItem extends DataItem {
+
+ public NicknameDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getName() {
+ return getContentValues().getAsString(Nickname.NAME);
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(Nickname.LABEL);
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/NoteDataItem.java b/src/com/android/contacts/common/model/dataitem/NoteDataItem.java
new file mode 100644
index 0000000..3d71167
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/NoteDataItem.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Note;
+
+/**
+ * Represents a note data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Note}.
+ */
+public class NoteDataItem extends DataItem {
+
+ /* package */ NoteDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getNote() {
+ return getContentValues().getAsString(Note.NOTE);
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/OrganizationDataItem.java b/src/com/android/contacts/common/model/dataitem/OrganizationDataItem.java
new file mode 100644
index 0000000..37cd852
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/OrganizationDataItem.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+
+/**
+ * Represents an organization data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Organization}.
+ */
+public class OrganizationDataItem extends DataItem {
+
+ /* package */ OrganizationDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getCompany() {
+ return getContentValues().getAsString(Organization.COMPANY);
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(Organization.LABEL);
+ }
+
+ public String getTitle() {
+ return getContentValues().getAsString(Organization.TITLE);
+ }
+
+ public String getDepartment() {
+ return getContentValues().getAsString(Organization.DEPARTMENT);
+ }
+
+ public String getJobDescription() {
+ return getContentValues().getAsString(Organization.JOB_DESCRIPTION);
+ }
+
+ public String getSymbol() {
+ return getContentValues().getAsString(Organization.SYMBOL);
+ }
+
+ public String getPhoneticName() {
+ return getContentValues().getAsString(Organization.PHONETIC_NAME);
+ }
+
+ public String getOfficeLocation() {
+ return getContentValues().getAsString(Organization.OFFICE_LOCATION);
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/PhoneDataItem.java b/src/com/android/contacts/common/model/dataitem/PhoneDataItem.java
new file mode 100644
index 0000000..d6aa2a9
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/PhoneDataItem.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+
+import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
+import com.android.contacts.common.model.dataitem.DataKind;
+
+/**
+ * Represents a phone data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Phone}.
+ */
+public class PhoneDataItem extends DataItem {
+
+ public static final String KEY_FORMATTED_PHONE_NUMBER = "formattedPhoneNumber";
+
+ /* package */ PhoneDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getNumber() {
+ return getContentValues().getAsString(Phone.NUMBER);
+ }
+
+ /**
+ * Returns the normalized phone number in E164 format.
+ */
+ public String getNormalizedNumber() {
+ return getContentValues().getAsString(Phone.NORMALIZED_NUMBER);
+ }
+
+ public String getFormattedPhoneNumber() {
+ return getContentValues().getAsString(KEY_FORMATTED_PHONE_NUMBER);
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(Phone.LABEL);
+ }
+
+ public void computeFormattedPhoneNumber(String defaultCountryIso) {
+ final String phoneNumber = getNumber();
+ if (phoneNumber != null) {
+ final String formattedPhoneNumber = PhoneNumberUtilsCompat.formatNumber(phoneNumber,
+ getNormalizedNumber(), defaultCountryIso);
+ getContentValues().put(KEY_FORMATTED_PHONE_NUMBER, formattedPhoneNumber);
+ }
+ }
+
+ /**
+ * Returns the formatted phone number (if already computed using {@link
+ * #computeFormattedPhoneNumber}). Otherwise this method returns the unformatted phone number.
+ */
+ @Override
+ public String buildDataStringForDisplay(Context context, DataKind kind) {
+ final String formatted = getFormattedPhoneNumber();
+ if (formatted != null) {
+ return formatted;
+ } else {
+ return getNumber();
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/PhotoDataItem.java b/src/com/android/contacts/common/model/dataitem/PhotoDataItem.java
new file mode 100644
index 0000000..a61218b
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/PhotoDataItem.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts.Photo;
+
+/**
+ * Represents a photo data item, wrapping the columns in
+ * {@link ContactsContract.Contacts.Photo}.
+ */
+public class PhotoDataItem extends DataItem {
+
+ /* package */ PhotoDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public Long getPhotoFileId() {
+ return getContentValues().getAsLong(Photo.PHOTO_FILE_ID);
+ }
+
+ public byte[] getPhoto() {
+ return getContentValues().getAsByteArray(Photo.PHOTO);
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/RelationDataItem.java b/src/com/android/contacts/common/model/dataitem/RelationDataItem.java
new file mode 100644
index 0000000..9e883fe
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/RelationDataItem.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Relation;
+import android.text.TextUtils;
+
+/**
+ * Represents a relation data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Relation}.
+ */
+public class RelationDataItem extends DataItem {
+
+ /* package */ RelationDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getName() {
+ return getContentValues().getAsString(Relation.NAME);
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(Relation.LABEL);
+ }
+
+ @Override
+ public boolean shouldCollapseWith(DataItem t, Context context) {
+ if (!(t instanceof RelationDataItem) || mKind == null || t.getDataKind() == null) {
+ return false;
+ }
+ final RelationDataItem that = (RelationDataItem) t;
+ // Relations can have different types (assistant, father) but have the same name
+ if (!TextUtils.equals(getName(), that.getName())) {
+ return false;
+ } else if (!hasKindTypeColumn(mKind) || !that.hasKindTypeColumn(that.getDataKind())) {
+ return hasKindTypeColumn(mKind) == that.hasKindTypeColumn(that.getDataKind());
+ } else if (getKindTypeColumn(mKind) != that.getKindTypeColumn(that.getDataKind())) {
+ return false;
+ } else if (getKindTypeColumn(mKind) == Relation.TYPE_CUSTOM &&
+ !TextUtils.equals(getLabel(), that.getLabel())) {
+ // Check if custom types are not the same
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/SipAddressDataItem.java b/src/com/android/contacts/common/model/dataitem/SipAddressDataItem.java
new file mode 100644
index 0000000..ec704fc
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/SipAddressDataItem.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+
+/**
+ * Represents a sip address data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.SipAddress}.
+ */
+public class SipAddressDataItem extends DataItem {
+
+ /* package */ SipAddressDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getSipAddress() {
+ return getContentValues().getAsString(SipAddress.SIP_ADDRESS);
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(SipAddress.LABEL);
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/StructuredNameDataItem.java b/src/com/android/contacts/common/model/dataitem/StructuredNameDataItem.java
new file mode 100644
index 0000000..4d463da
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/StructuredNameDataItem.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Contacts.Data;
+
+/**
+ * Represents a structured name data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.StructuredName}.
+ */
+public class StructuredNameDataItem extends DataItem {
+
+ public StructuredNameDataItem() {
+ super(new ContentValues());
+ getContentValues().put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ }
+
+ /* package */ StructuredNameDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getDisplayName() {
+ return getContentValues().getAsString(StructuredName.DISPLAY_NAME);
+ }
+
+ public void setDisplayName(String name) {
+ getContentValues().put(StructuredName.DISPLAY_NAME, name);
+ }
+
+ public String getGivenName() {
+ return getContentValues().getAsString(StructuredName.GIVEN_NAME);
+ }
+
+ public String getFamilyName() {
+ return getContentValues().getAsString(StructuredName.FAMILY_NAME);
+ }
+
+ public String getPrefix() {
+ return getContentValues().getAsString(StructuredName.PREFIX);
+ }
+
+ public String getMiddleName() {
+ return getContentValues().getAsString(StructuredName.MIDDLE_NAME);
+ }
+
+ public String getSuffix() {
+ return getContentValues().getAsString(StructuredName.SUFFIX);
+ }
+
+ public String getPhoneticGivenName() {
+ return getContentValues().getAsString(StructuredName.PHONETIC_GIVEN_NAME);
+ }
+
+ public String getPhoneticMiddleName() {
+ return getContentValues().getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
+ }
+
+ public String getPhoneticFamilyName() {
+ return getContentValues().getAsString(StructuredName.PHONETIC_FAMILY_NAME);
+ }
+
+ public String getFullNameStyle() {
+ return getContentValues().getAsString(StructuredName.FULL_NAME_STYLE);
+ }
+
+ public void setPhoneticFamilyName(String name) {
+ getContentValues().put(StructuredName.PHONETIC_FAMILY_NAME, name);
+ }
+
+ public void setPhoneticMiddleName(String name) {
+ getContentValues().put(StructuredName.PHONETIC_MIDDLE_NAME, name);
+ }
+
+ public void setPhoneticGivenName(String name) {
+ getContentValues().put(StructuredName.PHONETIC_GIVEN_NAME, name);
+ }
+
+ public boolean isSuperPrimary() {
+ final ContentValues contentValues = getContentValues();
+ return contentValues == null || !contentValues.containsKey(StructuredName.IS_SUPER_PRIMARY)
+ ? false : contentValues.getAsBoolean(StructuredName.IS_SUPER_PRIMARY);
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/StructuredPostalDataItem.java b/src/com/android/contacts/common/model/dataitem/StructuredPostalDataItem.java
new file mode 100644
index 0000000..6cfc0c1
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/StructuredPostalDataItem.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+
+/**
+ * Represents a structured postal data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.StructuredPostal}.
+ */
+public class StructuredPostalDataItem extends DataItem {
+
+ /* package */ StructuredPostalDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getFormattedAddress() {
+ return getContentValues().getAsString(StructuredPostal.FORMATTED_ADDRESS);
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(StructuredPostal.LABEL);
+ }
+
+ public String getStreet() {
+ return getContentValues().getAsString(StructuredPostal.STREET);
+ }
+
+ public String getPOBox() {
+ return getContentValues().getAsString(StructuredPostal.POBOX);
+ }
+
+ public String getNeighborhood() {
+ return getContentValues().getAsString(StructuredPostal.NEIGHBORHOOD);
+ }
+
+ public String getCity() {
+ return getContentValues().getAsString(StructuredPostal.CITY);
+ }
+
+ public String getRegion() {
+ return getContentValues().getAsString(StructuredPostal.REGION);
+ }
+
+ public String getPostcode() {
+ return getContentValues().getAsString(StructuredPostal.POSTCODE);
+ }
+
+ public String getCountry() {
+ return getContentValues().getAsString(StructuredPostal.COUNTRY);
+ }
+}
diff --git a/src/com/android/contacts/common/model/dataitem/WebsiteDataItem.java b/src/com/android/contacts/common/model/dataitem/WebsiteDataItem.java
new file mode 100644
index 0000000..0939421
--- /dev/null
+++ b/src/com/android/contacts/common/model/dataitem/WebsiteDataItem.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 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.common.model.dataitem;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+
+/**
+ * Represents a website data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Website}.
+ */
+public class WebsiteDataItem extends DataItem {
+
+ /* package */ WebsiteDataItem(ContentValues values) {
+ super(values);
+ }
+
+ public String getUrl() {
+ return getContentValues().getAsString(Website.URL);
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(Website.LABEL);
+ }
+}
diff --git a/src/com/android/contacts/common/preference/AboutPreferenceFragment.java b/src/com/android/contacts/common/preference/AboutPreferenceFragment.java
new file mode 100644
index 0000000..3b5a28d
--- /dev/null
+++ b/src/com/android/contacts/common/preference/AboutPreferenceFragment.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 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.common.preference;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+import android.widget.Toast;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.activity.LicenseActivity;
+
+/**
+ * This fragment shows the preferences for "about".
+ */
+public class AboutPreferenceFragment extends PreferenceFragment {
+
+ private static final String PRIVACY_POLICY_URL = "http://www.google.com/policies/privacy";
+ private static final String TERMS_OF_SERVICE_URL = "http://www.google.com/policies/terms";
+
+ public static AboutPreferenceFragment newInstance() {
+ return new AboutPreferenceFragment();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Load the preferences from an XML resource
+ addPreferencesFromResource(R.xml.preference_about);
+
+ // Set build version of Contacts App.
+ final PackageManager manager = getActivity().getPackageManager();
+ try {
+ final PackageInfo info = manager.getPackageInfo(getActivity().getPackageName(), 0);
+ final Preference versionPreference = findPreference(
+ getString(R.string.pref_build_version_key));
+ versionPreference.setSummary(info.versionName);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Nothing
+ }
+
+ final Preference licensePreference = findPreference(
+ getString(R.string.pref_open_source_licenses_key));
+ licensePreference.setIntent(new Intent(getActivity(), LicenseActivity.class));
+
+ final Preference privacyPolicyPreference = findPreference("pref_privacy_policy");
+ final Preference termsOfServicePreference = findPreference("pref_terms_of_service");
+
+ final Preference.OnPreferenceClickListener listener =
+ new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ try {
+ if (preference == privacyPolicyPreference) {
+ startActivityForUrl(PRIVACY_POLICY_URL);
+ } else if (preference == termsOfServicePreference) {
+ startActivityForUrl(TERMS_OF_SERVICE_URL);
+ }
+ } catch (ActivityNotFoundException ex) {
+ Toast.makeText(getContext(), getString(R.string.url_open_error_toast),
+ Toast.LENGTH_SHORT).show();
+ }
+ return true;
+ }
+ };
+
+ privacyPolicyPreference.setOnPreferenceClickListener(listener);
+ termsOfServicePreference.setOnPreferenceClickListener(listener);
+ }
+
+ @Override
+ public Context getContext() {
+ return getActivity();
+ }
+
+ private void startActivityForUrl(String urlString) {
+ final Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(urlString));
+ startActivity(intent);
+ }
+}
+
diff --git a/src/com/android/contacts/common/preference/ContactsPreferenceActivity.java b/src/com/android/contacts/common/preference/ContactsPreferenceActivity.java
new file mode 100644
index 0000000..dbf3cb9
--- /dev/null
+++ b/src/com/android/contacts/common/preference/ContactsPreferenceActivity.java
@@ -0,0 +1,142 @@
+/*
+ * 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.common.preference;
+
+import android.app.ActionBar;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.provider.ContactsContract.ProviderStatus;
+import android.provider.ContactsContract.QuickContact;
+import android.text.TextUtils;
+import android.view.MenuItem;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.list.ProviderStatusWatcher;
+import com.android.contacts.common.preference.DisplayOptionsPreferenceFragment.ProfileListener;
+import com.android.contacts.common.preference.DisplayOptionsPreferenceFragment.ProfileQuery;
+
+/**
+ * Contacts settings.
+ */
+public final class ContactsPreferenceActivity extends PreferenceActivity implements
+ ProfileListener {
+
+ private static final String TAG_ABOUT = "about_contacts";
+ private static final String TAG_DISPLAY_OPTIONS = "display_options";
+
+ private String mNewLocalProfileExtra;
+ private String mPreviousScreenExtra;
+ private int mModeFullyExpanded;
+ private boolean mAreContactsAvailable;
+
+ private ProviderStatusWatcher mProviderStatusWatcher;
+
+ public static final String EXTRA_NEW_LOCAL_PROFILE = "newLocalProfile";
+ public static final String EXTRA_MODE_FULLY_EXPANDED = "modeFullyExpanded";
+ public static final String EXTRA_PREVIOUS_SCREEN_TYPE = "previousScreenType";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
+ }
+
+ mProviderStatusWatcher = ProviderStatusWatcher.getInstance(this);
+
+ mNewLocalProfileExtra = getIntent().getStringExtra(EXTRA_NEW_LOCAL_PROFILE);
+ mModeFullyExpanded = getIntent().getIntExtra(EXTRA_MODE_FULLY_EXPANDED,
+ QuickContact.MODE_LARGE);
+ mPreviousScreenExtra = getIntent().getStringExtra(EXTRA_PREVIOUS_SCREEN_TYPE);
+ final int providerStatus = mProviderStatusWatcher.getProviderStatus();
+ mAreContactsAvailable = providerStatus == ProviderStatus.STATUS_NORMAL;
+
+ if (savedInstanceState == null) {
+ final DisplayOptionsPreferenceFragment fragment = DisplayOptionsPreferenceFragment
+ .newInstance(mNewLocalProfileExtra, mPreviousScreenExtra, mModeFullyExpanded,
+ mAreContactsAvailable);
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, fragment, TAG_DISPLAY_OPTIONS)
+ .commit();
+ setActivityTitle(R.string.activity_title_settings);
+ } else {
+ final AboutPreferenceFragment aboutFragment = (AboutPreferenceFragment)
+ getFragmentManager().findFragmentByTag(TAG_ABOUT);
+
+ if (aboutFragment != null) {
+ setActivityTitle(R.string.setting_about);
+ } else {
+ setActivityTitle(R.string.activity_title_settings);
+ }
+ }
+ }
+
+ protected void showAboutFragment() {
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, AboutPreferenceFragment.newInstance(), TAG_ABOUT)
+ .addToBackStack(null)
+ .commit();
+ setActivityTitle(R.string.setting_about);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (getFragmentManager().getBackStackEntryCount() > 0) {
+ setActivityTitle(R.string.activity_title_settings);
+ getFragmentManager().popBackStack();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ private void setActivityTitle(int res) {
+ final ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ actionBar.setTitle(res);
+ }
+ }
+
+ @Override
+ public void onProfileLoaded(Cursor cursor) {
+ boolean hasProfile = false;
+ String displayName = null;
+ long contactId = -1;
+ if (cursor != null && cursor.moveToFirst()) {
+ hasProfile = cursor.getInt(ProfileQuery.CONTACT_IS_USER_PROFILE) == 1;
+ displayName = cursor.getString(ProfileQuery.CONTACT_DISPLAY_NAME);
+ contactId = cursor.getLong(ProfileQuery.CONTACT_ID);
+ }
+ if (hasProfile && TextUtils.isEmpty(displayName)) {
+ displayName = getString(R.string.missing_name);
+ }
+ final DisplayOptionsPreferenceFragment fragment = (DisplayOptionsPreferenceFragment)
+ getFragmentManager().findFragmentByTag(TAG_DISPLAY_OPTIONS);
+ fragment.updateMyInfoPreference(hasProfile, displayName, contactId);
+ }
+}
diff --git a/src/com/android/contacts/common/preference/ContactsPreferences.java b/src/com/android/contacts/common/preference/ContactsPreferences.java
new file mode 100644
index 0000000..a8a9089
--- /dev/null
+++ b/src/com/android/contacts/common/preference/ContactsPreferences.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2010 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.common.preference;
+
+import android.accounts.Account;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.provider.ContactsContract;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.text.TextUtils;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.model.AccountTypeManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages user preferences for contacts.
+ */
+public class ContactsPreferences implements OnSharedPreferenceChangeListener {
+
+ /**
+ * The value for the DISPLAY_ORDER key to show the given name first.
+ */
+ public static final int DISPLAY_ORDER_PRIMARY = 1;
+
+ /**
+ * The value for the DISPLAY_ORDER key to show the family name first.
+ */
+ public static final int DISPLAY_ORDER_ALTERNATIVE = 2;
+
+ public static final String DISPLAY_ORDER_KEY = "android.contacts.DISPLAY_ORDER";
+
+ /**
+ * The value for the SORT_ORDER key corresponding to sort by given name first.
+ */
+ public static final int SORT_ORDER_PRIMARY = 1;
+
+ public static final String SORT_ORDER_KEY = "android.contacts.SORT_ORDER";
+
+ /**
+ * The value for the SORT_ORDER key corresponding to sort by family name first.
+ */
+ public static final int SORT_ORDER_ALTERNATIVE = 2;
+
+ public static final String PREF_DISPLAY_ONLY_PHONES = "only_phones";
+
+ public static final boolean PREF_DISPLAY_ONLY_PHONES_DEFAULT = false;
+
+ public static final String DO_NOT_SYNC_CONTACT_METADATA_MSG = "Do not sync metadata";
+
+ public static final String CONTACT_METADATA_AUTHORITY = "com.android.contacts.metadata";
+
+ public static final String SHOULD_CLEAR_METADATA_BEFORE_SYNCING =
+ "should_clear_metadata_before_syncing";
+
+ public static final String ONLY_CLEAR_DONOT_SYNC = "only_clear_donot_sync";
+ /**
+ * Value to use when a preference is unassigned and needs to be read from the shared preferences
+ */
+ private static final int PREFERENCE_UNASSIGNED = -1;
+
+ private final Context mContext;
+ private int mSortOrder = PREFERENCE_UNASSIGNED;
+ private int mDisplayOrder = PREFERENCE_UNASSIGNED;
+ private String mDefaultAccount = null;
+ private ChangeListener mListener = null;
+ private Handler mHandler;
+ private final SharedPreferences mPreferences;
+ private String mDefaultAccountKey;
+ private String mDefaultAccountSavedKey;
+
+ public ContactsPreferences(Context context) {
+ mContext = context;
+ mHandler = new Handler();
+ mPreferences = mContext.getSharedPreferences(context.getPackageName(),
+ Context.MODE_PRIVATE);
+ mDefaultAccountKey = mContext.getResources().getString(
+ R.string.contact_editor_default_account_key);
+ mDefaultAccountSavedKey = mContext.getResources().getString(
+ R.string.contact_editor_anything_saved_key);
+ maybeMigrateSystemSettings();
+ }
+
+ public boolean isSortOrderUserChangeable() {
+ return mContext.getResources().getBoolean(R.bool.config_sort_order_user_changeable);
+ }
+
+ public int getDefaultSortOrder() {
+ if (mContext.getResources().getBoolean(R.bool.config_default_sort_order_primary)) {
+ return SORT_ORDER_PRIMARY;
+ } else {
+ return SORT_ORDER_ALTERNATIVE;
+ }
+ }
+
+ public int getSortOrder() {
+ if (!isSortOrderUserChangeable()) {
+ return getDefaultSortOrder();
+ }
+ if (mSortOrder == PREFERENCE_UNASSIGNED) {
+ mSortOrder = mPreferences.getInt(SORT_ORDER_KEY, getDefaultSortOrder());
+ }
+ return mSortOrder;
+ }
+
+ public void setSortOrder(int sortOrder) {
+ mSortOrder = sortOrder;
+ final Editor editor = mPreferences.edit();
+ editor.putInt(SORT_ORDER_KEY, sortOrder);
+ editor.commit();
+ }
+
+ public boolean isDisplayOrderUserChangeable() {
+ return mContext.getResources().getBoolean(R.bool.config_display_order_user_changeable);
+ }
+
+ public int getDefaultDisplayOrder() {
+ if (mContext.getResources().getBoolean(R.bool.config_default_display_order_primary)) {
+ return DISPLAY_ORDER_PRIMARY;
+ } else {
+ return DISPLAY_ORDER_ALTERNATIVE;
+ }
+ }
+
+ public int getDisplayOrder() {
+ if (!isDisplayOrderUserChangeable()) {
+ return getDefaultDisplayOrder();
+ }
+ if (mDisplayOrder == PREFERENCE_UNASSIGNED) {
+ mDisplayOrder = mPreferences.getInt(DISPLAY_ORDER_KEY, getDefaultDisplayOrder());
+ }
+ return mDisplayOrder;
+ }
+
+ public void setDisplayOrder(int displayOrder) {
+ mDisplayOrder = displayOrder;
+ final Editor editor = mPreferences.edit();
+ editor.putInt(DISPLAY_ORDER_KEY, displayOrder);
+ editor.commit();
+ }
+
+ public boolean isDefaultAccountUserChangeable() {
+ return mContext.getResources().getBoolean(R.bool.config_default_account_user_changeable);
+ }
+
+ public String getDefaultAccount() {
+ if (!isDefaultAccountUserChangeable()) {
+ return mDefaultAccount;
+ }
+ if (TextUtils.isEmpty(mDefaultAccount)) {
+ final String accountString = mPreferences
+ .getString(mDefaultAccountKey, mDefaultAccount);
+ if (!TextUtils.isEmpty(accountString)) {
+ final AccountWithDataSet accountWithDataSet = AccountWithDataSet.unstringify(
+ accountString);
+ mDefaultAccount = accountWithDataSet.name;
+ }
+ }
+ return mDefaultAccount;
+ }
+
+ public void setDefaultAccount(AccountWithDataSet accountWithDataSet) {
+ mDefaultAccount = accountWithDataSet == null ? null : accountWithDataSet.name;
+ final Editor editor = mPreferences.edit();
+ if (TextUtils.isEmpty(mDefaultAccount)) {
+ editor.remove(mDefaultAccountKey);
+ } else {
+ editor.putString(mDefaultAccountKey, accountWithDataSet.stringify());
+ }
+ editor.putBoolean(mDefaultAccountSavedKey, true);
+ editor.commit();
+ }
+
+ public String getContactMetadataSyncAccountName() {
+ final Account syncAccount = getContactMetadataSyncAccount();
+ return syncAccount == null ? DO_NOT_SYNC_CONTACT_METADATA_MSG : syncAccount.name;
+ }
+
+ public void setContactMetadataSyncAccount(AccountWithDataSet accountWithDataSet) {
+ final String mContactMetadataSyncAccount =
+ accountWithDataSet == null ? null : accountWithDataSet.name;
+ requestMetadataSyncForAccount(mContactMetadataSyncAccount);
+ }
+
+ private Account getContactMetadataSyncAccount() {
+ for (Account account : getFocusGoogleAccounts()) {
+ if (ContentResolver.getIsSyncable(account, CONTACT_METADATA_AUTHORITY) == 1
+ && ContentResolver.getSyncAutomatically(account, CONTACT_METADATA_AUTHORITY)) {
+ return account;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Turn on contact metadata sync for this {@param accountName} and turn off automatic sync
+ * for other accounts. If accountName is null, then turn off automatic sync for all accounts.
+ */
+ private void requestMetadataSyncForAccount(String accountName) {
+ for (Account account : getFocusGoogleAccounts()) {
+ if (!TextUtils.isEmpty(accountName) && accountName.equals(account.name)) {
+ // Request sync.
+ final Bundle b = new Bundle();
+ b.putBoolean(SHOULD_CLEAR_METADATA_BEFORE_SYNCING, true);
+ b.putBoolean(ONLY_CLEAR_DONOT_SYNC, false);
+ b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+ ContentResolver.requestSync(account, CONTACT_METADATA_AUTHORITY, b);
+
+ ContentResolver.setSyncAutomatically(account, CONTACT_METADATA_AUTHORITY, true);
+ } else if (ContentResolver.getSyncAutomatically(account, CONTACT_METADATA_AUTHORITY)) {
+ // Turn off automatic sync for previous sync account.
+ ContentResolver.setSyncAutomatically(account, CONTACT_METADATA_AUTHORITY, false);
+ if (TextUtils.isEmpty(accountName)) {
+ // Request sync to clear old data.
+ final Bundle b = new Bundle();
+ b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+ b.putBoolean(SHOULD_CLEAR_METADATA_BEFORE_SYNCING, true);
+ b.putBoolean(ONLY_CLEAR_DONOT_SYNC, true);
+ ContentResolver.requestSync(account, CONTACT_METADATA_AUTHORITY, b);
+ }
+ }
+ }
+ }
+
+ /**
+ * @return google accounts with "com.google" account type and null data set.
+ */
+ private List<Account> getFocusGoogleAccounts() {
+ List<Account> focusGoogleAccounts = new ArrayList<Account>();
+ final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(mContext);
+ List<AccountWithDataSet> accounts = accountTypeManager.getAccounts(true);
+ for (AccountWithDataSet account : accounts) {
+ if (GoogleAccountType.ACCOUNT_TYPE.equals(account.type) && account.dataSet == null) {
+ focusGoogleAccounts.add(account.getAccountOrNull());
+ }
+ }
+ return focusGoogleAccounts;
+ }
+
+ public void registerChangeListener(ChangeListener listener) {
+ if (mListener != null) unregisterChangeListener();
+
+ mListener = listener;
+
+ // Reset preferences to "unknown" because they may have changed while the
+ // listener was unregistered.
+ mDisplayOrder = PREFERENCE_UNASSIGNED;
+ mSortOrder = PREFERENCE_UNASSIGNED;
+ mDefaultAccount = null;
+
+ mPreferences.registerOnSharedPreferenceChangeListener(this);
+ }
+
+ public void unregisterChangeListener() {
+ if (mListener != null) {
+ mListener = null;
+ }
+
+ mPreferences.unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, final String key) {
+ // This notification is not sent on the Ui thread. Use the previously created Handler
+ // to switch to the Ui thread
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ refreshValue(key);
+ }
+ });
+ }
+
+ /**
+ * Forces the value for the given key to be looked up from shared preferences and notifies
+ * the registered {@link ChangeListener}
+ *
+ * @param key the {@link SharedPreferences} key to look up
+ */
+ public void refreshValue(String key) {
+ if (DISPLAY_ORDER_KEY.equals(key)) {
+ mDisplayOrder = PREFERENCE_UNASSIGNED;
+ mDisplayOrder = getDisplayOrder();
+ } else if (SORT_ORDER_KEY.equals(key)) {
+ mSortOrder = PREFERENCE_UNASSIGNED;
+ mSortOrder = getSortOrder();
+ } else if (mDefaultAccountKey.equals(key)) {
+ mDefaultAccount = null;
+ mDefaultAccount = getDefaultAccount();
+ }
+ if (mListener != null) mListener.onChange();
+ }
+
+ public interface ChangeListener {
+ void onChange();
+ }
+
+ /**
+ * If there are currently no preferences (which means this is the first time we are run),
+ * For sort order and display order, check to see if there are any preferences stored in
+ * system settings (pre-L) which can be copied into our own SharedPreferences.
+ * For default account setting, check to see if there are any preferences stored in the previous
+ * SharedPreferences which can be copied into current SharedPreferences.
+ */
+ private void maybeMigrateSystemSettings() {
+ if (!mPreferences.contains(SORT_ORDER_KEY)) {
+ int sortOrder = getDefaultSortOrder();
+ try {
+ sortOrder = Settings.System.getInt(mContext.getContentResolver(),
+ SORT_ORDER_KEY);
+ } catch (SettingNotFoundException e) {
+ }
+ setSortOrder(sortOrder);
+ }
+
+ if (!mPreferences.contains(DISPLAY_ORDER_KEY)) {
+ int displayOrder = getDefaultDisplayOrder();
+ try {
+ displayOrder = Settings.System.getInt(mContext.getContentResolver(),
+ DISPLAY_ORDER_KEY);
+ } catch (SettingNotFoundException e) {
+ }
+ setDisplayOrder(displayOrder);
+ }
+
+ if (!mPreferences.contains(mDefaultAccountKey)) {
+ final SharedPreferences previousPrefs =
+ PreferenceManager.getDefaultSharedPreferences(mContext);
+ final String defaultAccount = previousPrefs.getString(mDefaultAccountKey, null);
+ if (!TextUtils.isEmpty(defaultAccount)) {
+ final AccountWithDataSet accountWithDataSet = AccountWithDataSet.unstringify(
+ defaultAccount);
+ setDefaultAccount(accountWithDataSet);
+ }
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/preference/DefaultAccountPreference.java b/src/com/android/contacts/common/preference/DefaultAccountPreference.java
new file mode 100644
index 0000000..2fc5c7b
--- /dev/null
+++ b/src/com/android/contacts/common/preference/DefaultAccountPreference.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 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.common.preference;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.preference.ListPreference;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountTypeWithDataSet;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class DefaultAccountPreference extends ListPreference {
+ private ContactsPreferences mPreferences;
+ private Map<String, AccountWithDataSet> mAccountMap;
+
+ public DefaultAccountPreference(Context context) {
+ super(context);
+ prepare();
+ }
+
+ public DefaultAccountPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ prepare();
+ }
+
+ @Override
+ protected View onCreateDialogView() {
+ prepare();
+ return super.onCreateDialogView();
+ }
+
+ private void prepare() {
+ mPreferences = new ContactsPreferences(getContext());
+ mAccountMap = new HashMap<>();
+ final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(getContext());
+ List<AccountWithDataSet> accounts = accountTypeManager.getAccounts(true);
+ for (AccountWithDataSet account : accounts) {
+ mAccountMap.put(account.name, account);
+ }
+ final Set<String> accountNames = mAccountMap.keySet();
+ final String[] accountNamesArray = accountNames.toArray(new String[accountNames.size()]);
+ setEntries(accountNamesArray);
+ setEntryValues(accountNamesArray);
+ final String defaultAccount = String.valueOf(mPreferences.getDefaultAccount());
+ if (accounts.size() == 1) {
+ setValue(accounts.get(0).name);
+ } else if (accountNames.contains(defaultAccount)) {
+ setValue(defaultAccount);
+ } else {
+ setValue(null);
+ }
+ }
+
+ @Override
+ protected boolean shouldPersist() {
+ return false; // This preference takes care of its own storage
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return mPreferences.getDefaultAccount();
+ }
+
+ @Override
+ protected boolean persistString(String value) {
+ if (value == null && mPreferences.getDefaultAccount() == null) {
+ return true;
+ }
+ if (value == null || mPreferences.getDefaultAccount() == null
+ || !value.equals(mPreferences.getDefaultAccount())) {
+ mPreferences.setDefaultAccount(mAccountMap.get(value));
+ notifyChanged();
+ }
+ return true;
+ }
+
+ @Override
+ // UX recommendation is not to show cancel button on such lists.
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+ builder.setNegativeButton(null, null);
+ }
+}
diff --git a/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java b/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java
new file mode 100644
index 0000000..6afcb13
--- /dev/null
+++ b/src/com/android/contacts/common/preference/DisplayOptionsPreferenceFragment.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2010 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.common.preference;
+
+import android.app.Activity;
+import android.app.LoaderManager;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Intent;
+import android.content.Loader;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+import android.provider.BlockedNumberContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Profile;
+import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
+
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.TelecomManagerUtil;
+import com.android.contacts.common.compat.TelephonyManagerCompat;
+import com.android.contacts.common.interactions.ImportExportDialogFragment;
+import com.android.contacts.common.list.ContactListFilter;
+import com.android.contacts.common.list.ContactListFilterController;
+import com.android.contacts.common.logging.ScreenEvent.ScreenType;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.util.AccountFilterUtil;
+import com.android.contacts.common.util.ImplicitIntentsUtil;
+import com.android.contactsbind.ObjectFactory;
+
+import java.util.List;
+
+/**
+ * This fragment shows the preferences for "display options"
+ */
+public class DisplayOptionsPreferenceFragment extends PreferenceFragment
+ implements Preference.OnPreferenceClickListener {
+
+ private static final int REQUEST_CODE_CUSTOM_CONTACTS_FILTER = 0;
+
+ private static final String ARG_CONTACTS_AVAILABLE = "are_contacts_available";
+ private static final String ARG_MODE_FULLY_EXPANDED = "mode_fully_expanded";
+ private static final String ARG_NEW_LOCAL_PROFILE = "new_local_profile";
+ private static final String ARG_PREVIOUS_SCREEN = "previous_screen";
+
+ private static final String KEY_ABOUT = "about";
+ private static final String KEY_ACCOUNTS = "accounts";
+ private static final String KEY_DEFAULT_ACCOUNT = "defaultAccount";
+ private static final String KEY_BLOCKED_NUMBERS = "blockedNumbers";
+ private static final String KEY_DISPLAY_ORDER = "displayOrder";
+ private static final String KEY_CUSTOM_CONTACTS_FILTER = "customContactsFilter";
+ private static final String KEY_IMPORT_EXPORT = "importExport";
+ private static final String KEY_MY_INFO = "myInfo";
+ private static final String KEY_SORT_ORDER = "sortOrder";
+
+ private static final int LOADER_PROFILE = 0;
+
+ /**
+ * Callbacks for hosts of the {@link DisplayOptionsPreferenceFragment}.
+ */
+ public interface ProfileListener {
+ /**
+ * Invoked after profile has been loaded.
+ */
+ void onProfileLoaded(Cursor data);
+ }
+
+ /**
+ * The projections that are used to obtain user profile
+ */
+ public static class ProfileQuery {
+ /**
+ * Not instantiable.
+ */
+ private ProfileQuery() {}
+
+ private static final String[] PROFILE_PROJECTION_PRIMARY = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_PRIMARY, // 1
+ Contacts.IS_USER_PROFILE, // 2
+ };
+
+ private static final String[] PROFILE_PROJECTION_ALTERNATIVE = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_ALTERNATIVE, // 1
+ Contacts.IS_USER_PROFILE, // 2
+ };
+
+ public static final int CONTACT_ID = 0;
+ public static final int CONTACT_DISPLAY_NAME = 1;
+ public static final int CONTACT_IS_USER_PROFILE = 2;
+ }
+
+ private String mNewLocalProfileExtra;
+ private String mPreviousScreenExtra;
+ private int mModeFullyExpanded;
+ private boolean mAreContactsAvailable;
+
+ private boolean mHasProfile;
+ private long mProfileContactId;
+
+ private Preference mMyInfoPreference;
+
+ private ProfileListener mListener;
+
+ private final LoaderManager.LoaderCallbacks<Cursor> mProfileLoaderListener =
+ new LoaderManager.LoaderCallbacks<Cursor>() {
+
+ @Override
+ public CursorLoader onCreateLoader(int id, Bundle args) {
+ final CursorLoader loader = createCursorLoader(getContext());
+ loader.setUri(Profile.CONTENT_URI);
+ loader.setProjection(getProjection(getContext()));
+ return loader;
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ if (mListener != null) {
+ mListener.onProfileLoaded(data);
+ }
+ }
+
+ public void onLoaderReset(Loader<Cursor> loader) {
+ }
+ };
+
+ public static DisplayOptionsPreferenceFragment newInstance(String newLocalProfileExtra,
+ String previousScreenExtra, int modeFullyExpanded, boolean areContactsAvailable) {
+ final DisplayOptionsPreferenceFragment fragment = new DisplayOptionsPreferenceFragment();
+ final Bundle args = new Bundle();
+ args.putString(ARG_NEW_LOCAL_PROFILE, newLocalProfileExtra);
+ args.putString(ARG_PREVIOUS_SCREEN, previousScreenExtra);
+ args.putInt(ARG_MODE_FULLY_EXPANDED, modeFullyExpanded);
+ args.putBoolean(ARG_CONTACTS_AVAILABLE, areContactsAvailable);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ mListener = (ProfileListener) activity;
+ } catch (ClassCastException e) {
+ throw new ClassCastException(activity.toString() + " must implement ProfileListener");
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Load the preferences from an XML resource
+ addPreferencesFromResource(R.xml.preference_display_options);
+
+ removeUnsupportedPreferences();
+ addExtraPreferences();
+
+ final Bundle args = getArguments();
+ mNewLocalProfileExtra = args.getString(ARG_NEW_LOCAL_PROFILE);
+ mPreviousScreenExtra = args.getString(ARG_PREVIOUS_SCREEN);
+ mModeFullyExpanded = args.getInt(ARG_MODE_FULLY_EXPANDED);
+ mAreContactsAvailable = args.getBoolean(ARG_CONTACTS_AVAILABLE);
+
+ mMyInfoPreference = findPreference(KEY_MY_INFO);
+
+ final Preference accountsPreference = findPreference(KEY_ACCOUNTS);
+ accountsPreference.setOnPreferenceClickListener(this);
+
+ final Preference importExportPreference = findPreference(KEY_IMPORT_EXPORT);
+ importExportPreference.setOnPreferenceClickListener(this);
+
+ final Preference blockedNumbersPreference = findPreference(KEY_BLOCKED_NUMBERS);
+ if (blockedNumbersPreference != null) {
+ blockedNumbersPreference.setOnPreferenceClickListener(this);
+ }
+
+ final Preference aboutPreference = findPreference(KEY_ABOUT);
+ aboutPreference.setOnPreferenceClickListener(this);
+
+ final Preference customFilterPreference = findPreference(KEY_CUSTOM_CONTACTS_FILTER);
+ if (customFilterPreference != null) {
+ customFilterPreference.setOnPreferenceClickListener(this);
+ setCustomContactsFilterSummary();
+ }
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ getLoaderManager().restartLoader(LOADER_PROFILE, null, mProfileLoaderListener);
+ }
+
+ public void updateMyInfoPreference(boolean hasProfile, String displayName, long contactId) {
+ final CharSequence summary = hasProfile ? displayName : getString(R.string.set_up_profile);
+ mMyInfoPreference.setSummary(summary);
+ mHasProfile = hasProfile;
+ mProfileContactId = contactId;
+ mMyInfoPreference.setOnPreferenceClickListener(this);
+ }
+
+ private void removeUnsupportedPreferences() {
+ // Disable sort order for CJK locales where it is not supported
+ final Resources resources = getResources();
+ if (!resources.getBoolean(R.bool.config_sort_order_user_changeable)) {
+ getPreferenceScreen().removePreference(findPreference(KEY_SORT_ORDER));
+ }
+
+ // Disable display order for CJK locales as well
+ if (!resources.getBoolean(R.bool.config_display_order_user_changeable)) {
+ getPreferenceScreen().removePreference(findPreference(KEY_DISPLAY_ORDER));
+ }
+
+ // Remove the "Default account" setting if there aren't any writable accounts
+ final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(getContext());
+ final List<AccountWithDataSet> accounts = accountTypeManager.getAccounts(
+ /* contactWritableOnly */ true);
+ if (accounts.isEmpty()) {
+ getPreferenceScreen().removePreference(findPreference(KEY_DEFAULT_ACCOUNT));
+ }
+
+ final boolean isPhone = TelephonyManagerCompat.isVoiceCapable(
+ (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE));
+ final boolean showBlockedNumbers = isPhone && ContactsUtils.FLAG_N_FEATURE
+ && BlockedNumberContract.canCurrentUserBlockNumbers(getContext());
+ if (!showBlockedNumbers) {
+ getPreferenceScreen().removePreference(findPreference(KEY_BLOCKED_NUMBERS));
+ }
+ }
+
+ private void addExtraPreferences() {
+ final PreferenceManager preferenceManager = ObjectFactory.getPreferenceManager(
+ getContext());
+ if (preferenceManager != null) {
+ for (Preference preference : preferenceManager.getPreferences()) {
+ getPreferenceScreen().addPreference(preference);
+ }
+ }
+ }
+
+ @Override
+ public Context getContext() {
+ return getActivity();
+ }
+
+ private CursorLoader createCursorLoader(Context context) {
+ return new CursorLoader(context) {
+ @Override
+ protected Cursor onLoadInBackground() {
+ try {
+ return super.onLoadInBackground();
+ } catch (RuntimeException e) {
+ return null;
+ }
+ }
+ };
+ }
+
+ private String[] getProjection(Context context) {
+ final ContactsPreferences contactsPrefs = new ContactsPreferences(context);
+ final int displayOrder = contactsPrefs.getDisplayOrder();
+ if (displayOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
+ return ProfileQuery.PROFILE_PROJECTION_PRIMARY;
+ }
+ return ProfileQuery.PROFILE_PROJECTION_ALTERNATIVE;
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference p) {
+ final String prefKey = p.getKey();
+
+ if (KEY_ABOUT.equals(prefKey)) {
+ ((ContactsPreferenceActivity) getActivity()).showAboutFragment();
+ return true;
+ } else if (KEY_IMPORT_EXPORT.equals(prefKey)) {
+ ImportExportDialogFragment.show(getFragmentManager(), mAreContactsAvailable,
+ ContactsPreferenceActivity.class,
+ ImportExportDialogFragment.EXPORT_MODE_ALL_CONTACTS);
+ return true;
+ } else if (KEY_MY_INFO.equals(prefKey)) {
+ final Intent intent;
+ if (mHasProfile) {
+ final Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, mProfileContactId);
+ intent = ImplicitIntentsUtil.composeQuickContactIntent(uri, mModeFullyExpanded);
+ intent.putExtra(mPreviousScreenExtra, ScreenType.ME_CONTACT);
+ } else {
+ intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
+ intent.putExtra(mNewLocalProfileExtra, true);
+ }
+ ImplicitIntentsUtil.startActivityInApp(getActivity(), intent);
+ return true;
+ } else if (KEY_ACCOUNTS.equals(prefKey)) {
+ ImplicitIntentsUtil.startActivityOutsideApp(getContext(),
+ ImplicitIntentsUtil.getIntentForAddingAccount());
+ return true;
+ } else if (KEY_BLOCKED_NUMBERS.equals(prefKey)) {
+ final Intent intent = TelecomManagerUtil.createManageBlockedNumbersIntent(
+ (TelecomManager) getContext().getSystemService(Context.TELECOM_SERVICE));
+ startActivity(intent);
+ return true;
+ } else if (KEY_CUSTOM_CONTACTS_FILTER.equals(prefKey)) {
+ final ContactListFilter filter =
+ ContactListFilterController.getInstance(getContext()).getFilter();
+ AccountFilterUtil.startAccountFilterActivityForResult(
+ this, REQUEST_CODE_CUSTOM_CONTACTS_FILTER, filter);
+ }
+ return false;
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_CODE_CUSTOM_CONTACTS_FILTER
+ && resultCode == Activity.RESULT_OK) {
+ AccountFilterUtil.handleAccountFilterResult(
+ ContactListFilterController.getInstance(getContext()), resultCode, data);
+ setCustomContactsFilterSummary();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ private void setCustomContactsFilterSummary() {
+ final Preference customFilterPreference = findPreference(KEY_CUSTOM_CONTACTS_FILTER);
+ if (customFilterPreference != null) {
+ final ContactListFilter filter =
+ ContactListFilterController.getInstance(getContext()).getPersistedFilter();
+ if (filter != null) {
+ if (filter.filterType == ContactListFilter.FILTER_TYPE_DEFAULT ||
+ filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS) {
+ customFilterPreference.setSummary(R.string.list_filter_all_accounts);
+ } else if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) {
+ customFilterPreference.setSummary(R.string.listCustomView);
+ } else {
+ customFilterPreference.setSummary(null);
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/com/android/contacts/common/preference/DisplayOrderPreference.java b/src/com/android/contacts/common/preference/DisplayOrderPreference.java
new file mode 100644
index 0000000..6a182c5
--- /dev/null
+++ b/src/com/android/contacts/common/preference/DisplayOrderPreference.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010 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.common.preference;
+
+import android.app.AlertDialog.Builder;
+import android.content.Context;
+import android.preference.ListPreference;
+import android.provider.ContactsContract;
+import android.util.AttributeSet;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.preference.ContactsPreferences;
+
+/**
+ * Custom preference: view-name-as (first name first or last name first).
+ */
+public final class DisplayOrderPreference extends ListPreference {
+
+ private ContactsPreferences mPreferences;
+ private Context mContext;
+
+ public DisplayOrderPreference(Context context) {
+ super(context);
+ prepare();
+ }
+
+ public DisplayOrderPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ prepare();
+ }
+
+ private void prepare() {
+ mContext = getContext();
+ mPreferences = new ContactsPreferences(mContext);
+ setEntries(new String[]{
+ mContext.getString(R.string.display_options_view_given_name_first),
+ mContext.getString(R.string.display_options_view_family_name_first),
+ });
+ setEntryValues(new String[]{
+ String.valueOf(ContactsPreferences.DISPLAY_ORDER_PRIMARY),
+ String.valueOf(ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE),
+ });
+ setValue(String.valueOf(mPreferences.getDisplayOrder()));
+ }
+
+ @Override
+ protected boolean shouldPersist() {
+ return false; // This preference takes care of its own storage
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ switch (mPreferences.getDisplayOrder()) {
+ case ContactsPreferences.DISPLAY_ORDER_PRIMARY:
+ return mContext.getString(R.string.display_options_view_given_name_first);
+ case ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE:
+ return mContext.getString(R.string.display_options_view_family_name_first);
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean persistString(String value) {
+ int newValue = Integer.parseInt(value);
+ if (newValue != mPreferences.getDisplayOrder()) {
+ mPreferences.setDisplayOrder(newValue);
+ notifyChanged();
+ }
+ return true;
+ }
+
+ @Override
+ // UX recommendation is not to show cancel button on such lists.
+ protected void onPrepareDialogBuilder(Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+ builder.setNegativeButton(null, null);
+ }
+}
diff --git a/src/com/android/contacts/common/preference/PreferenceManager.java b/src/com/android/contacts/common/preference/PreferenceManager.java
new file mode 100644
index 0000000..816f94e
--- /dev/null
+++ b/src/com/android/contacts/common/preference/PreferenceManager.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 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.common.preference;
+
+import android.preference.Preference;
+
+import java.util.List;
+
+public interface PreferenceManager {
+ List<Preference> getPreferences();
+}
diff --git a/src/com/android/contacts/common/preference/SortOrderPreference.java b/src/com/android/contacts/common/preference/SortOrderPreference.java
new file mode 100644
index 0000000..dfd9550
--- /dev/null
+++ b/src/com/android/contacts/common/preference/SortOrderPreference.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010 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.common.preference;
+
+import android.app.AlertDialog.Builder;
+import android.content.Context;
+import android.preference.ListPreference;
+import android.util.AttributeSet;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.preference.ContactsPreferences;
+
+/**
+ * Custom preference: sort-by.
+ */
+public final class SortOrderPreference extends ListPreference {
+
+ private ContactsPreferences mPreferences;
+ private Context mContext;
+
+ public SortOrderPreference(Context context) {
+ super(context);
+ prepare();
+ }
+
+ public SortOrderPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ prepare();
+ }
+
+ private void prepare() {
+ mContext = getContext();
+ mPreferences = new ContactsPreferences(mContext);
+ setEntries(new String[]{
+ mContext.getString(R.string.display_options_sort_by_given_name),
+ mContext.getString(R.string.display_options_sort_by_family_name),
+ });
+ setEntryValues(new String[]{
+ String.valueOf(ContactsPreferences.SORT_ORDER_PRIMARY),
+ String.valueOf(ContactsPreferences.SORT_ORDER_ALTERNATIVE),
+ });
+ setValue(String.valueOf(mPreferences.getSortOrder()));
+ }
+
+ @Override
+ protected boolean shouldPersist() {
+ return false; // This preference takes care of its own storage
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ switch (mPreferences.getSortOrder()) {
+ case ContactsPreferences.SORT_ORDER_PRIMARY:
+ return mContext.getString(R.string.display_options_sort_by_given_name);
+ case ContactsPreferences.SORT_ORDER_ALTERNATIVE:
+ return mContext.getString(R.string.display_options_sort_by_family_name);
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean persistString(String value) {
+ int newValue = Integer.parseInt(value);
+ if (newValue != mPreferences.getSortOrder()) {
+ mPreferences.setSortOrder(newValue);
+ notifyChanged();
+ }
+ return true;
+ }
+
+ @Override
+ // UX recommendation is not to show cancel button on such lists.
+ protected void onPrepareDialogBuilder(Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+ builder.setNegativeButton(null, null);
+ }
+}
diff --git a/src/com/android/contacts/common/testing/InjectedServices.java b/src/com/android/contacts/common/testing/InjectedServices.java
new file mode 100644
index 0000000..e89cec7
--- /dev/null
+++ b/src/com/android/contacts/common/testing/InjectedServices.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 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.common.testing;
+
+import android.content.ContentResolver;
+import android.content.SharedPreferences;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+
+import java.util.HashMap;
+
+/**
+ * A mechanism for providing alternative (mock) services to the application
+ * while running tests. Activities, Services and the Application should check
+ * with this class to see if a particular service has been overridden.
+ */
+@NeededForTesting
+public class InjectedServices {
+
+ private ContentResolver mContentResolver;
+ private SharedPreferences mSharedPreferences;
+ private HashMap<String, Object> mSystemServices;
+
+ @NeededForTesting
+ public void setContentResolver(ContentResolver contentResolver) {
+ this.mContentResolver = contentResolver;
+ }
+
+ public ContentResolver getContentResolver() {
+ return mContentResolver;
+ }
+
+ @NeededForTesting
+ public void setSharedPreferences(SharedPreferences sharedPreferences) {
+ this.mSharedPreferences = sharedPreferences;
+ }
+
+ public SharedPreferences getSharedPreferences() {
+ return mSharedPreferences;
+ }
+
+ @NeededForTesting
+ public void setSystemService(String name, Object service) {
+ if (mSystemServices == null) {
+ mSystemServices = Maps.newHashMap();
+ }
+
+ mSystemServices.put(name, service);
+ }
+
+ public Object getSystemService(String name) {
+ if (mSystemServices != null) {
+ return mSystemServices.get(name);
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/contacts/common/testing/NeededForTesting.java b/src/com/android/contacts/common/testing/NeededForTesting.java
new file mode 100644
index 0000000..f841d55
--- /dev/null
+++ b/src/com/android/contacts/common/testing/NeededForTesting.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 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.common.testing;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the class, constructor, method or field is used by tests and therefore cannot be
+ * removed by tools like ProGuard.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
+public @interface NeededForTesting {}
diff --git a/src/com/android/contacts/common/util/AccountFilterUtil.java b/src/com/android/contacts/common/util/AccountFilterUtil.java
new file mode 100644
index 0000000..76975a6
--- /dev/null
+++ b/src/com/android/contacts/common/util/AccountFilterUtil.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.list.AccountFilterActivity;
+import com.android.contacts.common.list.ContactListFilter;
+import com.android.contacts.common.list.ContactListFilterController;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class for account filter manipulation.
+ */
+public class AccountFilterUtil {
+ private static final String TAG = AccountFilterUtil.class.getSimpleName();
+
+ /**
+ * Launches account filter setting Activity using
+ * {@link Fragment#startActivityForResult(Intent, int)}.
+ *
+ * @param requestCode requestCode for {@link Activity#startActivityForResult(Intent, int)}
+ * @param currentFilter currently-selected filter, so that it can be displayed as activated.
+ */
+ public static void startAccountFilterActivityForResult(
+ Fragment fragment, int requestCode, ContactListFilter currentFilter) {
+ final Activity activity = fragment.getActivity();
+ if (activity != null) {
+ final Intent intent = new Intent(activity, AccountFilterActivity.class);
+ fragment.startActivityForResult(intent, requestCode);
+ } else {
+ Log.w(TAG, "getActivity() returned null. Ignored");
+ }
+ }
+
+ /**
+ * Useful method to handle onActivityResult() for
+ * {@link #startAccountFilterActivityForResult(Fragment, int, ContactListFilter)}.
+ *
+ * This will update filter via a given ContactListFilterController.
+ */
+ public static void handleAccountFilterResult(
+ ContactListFilterController filterController, int resultCode, Intent data) {
+ if (resultCode == Activity.RESULT_OK) {
+ final ContactListFilter filter = (ContactListFilter)
+ data.getParcelableExtra(AccountFilterActivity.EXTRA_CONTACT_LIST_FILTER);
+ if (filter == null) {
+ return;
+ }
+ if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) {
+ filterController.selectCustomFilter();
+ } else {
+ filterController.setContactListFilter(filter, /* persistent */
+ filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
+ }
+ }
+ }
+
+ /**
+ * Loads a list of contact list filters
+ */
+ public static class FilterLoader extends AsyncTaskLoader<List<ContactListFilter>> {
+ private Context mContext;
+
+ public FilterLoader(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ @Override
+ public List<ContactListFilter> loadInBackground() {
+ return loadAccountFilters(mContext);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ forceLoad();
+ }
+
+ @Override
+ protected void onStopLoading() {
+ cancelLoad();
+ }
+
+ @Override
+ protected void onReset() {
+ onStopLoading();
+ }
+ }
+
+ private static List<ContactListFilter> loadAccountFilters(Context context) {
+ final ArrayList<ContactListFilter> accountFilters = Lists.newArrayList();
+ final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(context);
+ accountTypeManager.sortAccounts(/* defaultAccount */ getDefaultAccount(context));
+ final List<AccountWithDataSet> accounts =
+ accountTypeManager.getAccounts(/* contactWritableOnly */ true);
+
+ for (AccountWithDataSet account : accounts) {
+ final AccountType accountType =
+ accountTypeManager.getAccountType(account.type, account.dataSet);
+ if (accountType.isExtension() && !account.hasData(context)) {
+ // Hide extensions with no raw_contacts.
+ continue;
+ }
+ final Drawable icon = accountType != null ? accountType.getDisplayIcon(context) : null;
+ if (account.isLocalAccount()) {
+ accountFilters.add(ContactListFilter.createDeviceContactsFilter(icon));
+ } else {
+ accountFilters.add(ContactListFilter.createAccountFilter(
+ account.type, account.name, account.dataSet, icon));
+ }
+ }
+
+ final ArrayList<ContactListFilter> result = Lists.newArrayList();
+ result.addAll(accountFilters);
+ return result;
+ }
+
+ private static AccountWithDataSet getDefaultAccount(Context context) {
+ final SharedPreferences prefs =
+ context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+ final String defaultAccountKey =
+ context.getResources().getString(R.string.contact_editor_default_account_key);
+ final String defaultAccountString = prefs.getString(defaultAccountKey, null);
+ if (TextUtils.isEmpty(defaultAccountString)) {
+ return null;
+ }
+ try {
+ return AccountWithDataSet.unstringify(defaultAccountString);
+ } catch (IllegalArgumentException exception) {
+ Log.e(TAG, "Error with retrieving default account " + exception.toString(), exception);
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/util/AccountSelectionUtil.java b/src/com/android/contacts/common/util/AccountSelectionUtil.java
new file mode 100644
index 0000000..4dc6ec9
--- /dev/null
+++ b/src/com/android/contacts/common/util/AccountSelectionUtil.java
@@ -0,0 +1,203 @@
+/*
+ * 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.common.util;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+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.ImageView;
+import android.widget.TextView;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.vcard.ImportVCardActivity;
+
+import java.util.List;
+
+/**
+ * Utility class for selecting an Account for importing contact(s)
+ */
+public class AccountSelectionUtil {
+ // TODO: maybe useful for EditContactActivity.java...
+ private static final String LOG_TAG = "AccountSelectionUtil";
+
+ public static boolean mVCardShare = false;
+
+ public static Uri mPath;
+
+ public static class AccountSelectedListener
+ implements DialogInterface.OnClickListener {
+
+ final private Context mContext;
+ final private int mResId;
+ final private int mSubscriptionId;
+
+ final protected List<AccountWithDataSet> mAccountList;
+
+ public AccountSelectedListener(Context context, List<AccountWithDataSet> accountList,
+ int resId, int subscriptionId) {
+ if (accountList == null || accountList.size() == 0) {
+ Log.e(LOG_TAG, "The size of Account list is 0.");
+ }
+ mContext = context;
+ mAccountList = accountList;
+ mResId = resId;
+ mSubscriptionId = subscriptionId;
+ }
+
+ public AccountSelectedListener(Context context, List<AccountWithDataSet> accountList,
+ int resId) {
+ // Subscription id is only needed for importing from SIM card. We can safely ignore
+ // its value for SD card importing.
+ this(context, accountList, resId, /* subscriptionId = */ -1);
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ doImport(mContext, mResId, mAccountList.get(which), mSubscriptionId);
+ }
+ }
+
+ public static Dialog getSelectAccountDialog(Context context, int resId) {
+ return getSelectAccountDialog(context, resId, null, null);
+ }
+
+ public static Dialog getSelectAccountDialog(Context context, int resId,
+ DialogInterface.OnClickListener onClickListener) {
+ return getSelectAccountDialog(context, resId, onClickListener, null);
+ }
+
+ /**
+ * When OnClickListener or OnCancelListener is null, uses a default listener.
+ * The default OnCancelListener just closes itself with {@link Dialog#dismiss()}.
+ */
+ public static Dialog getSelectAccountDialog(Context context, int resId,
+ DialogInterface.OnClickListener onClickListener,
+ DialogInterface.OnCancelListener onCancelListener) {
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
+ final List<AccountWithDataSet> writableAccountList = accountTypes.getAccounts(true);
+
+ Log.i(LOG_TAG, "The number of available accounts: " + writableAccountList.size());
+
+ // 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<AccountWithDataSet> accountAdapter =
+ new ArrayAdapter<AccountWithDataSet>(
+ context, R.layout.account_selector_list_item_condensed, writableAccountList) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = dialogInflater.inflate(
+ R.layout.account_selector_list_item_condensed,
+ parent, false);
+ }
+
+ final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1);
+ final TextView text2 = (TextView) convertView.findViewById(android.R.id.text2);
+ final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
+
+ final AccountWithDataSet account = this.getItem(position);
+ final AccountType accountType = accountTypes.getAccountType(
+ account.type, account.dataSet);
+ final Context context = getContext();
+
+ text1.setText(accountType.getDisplayLabel(context));
+ text2.setText(account.name);
+ icon.setImageDrawable(accountType.getDisplayIcon(getContext()));
+
+ return convertView;
+ }
+ };
+
+ if (onClickListener == null) {
+ AccountSelectedListener accountSelectedListener =
+ new AccountSelectedListener(context, writableAccountList, resId);
+ onClickListener = accountSelectedListener;
+ }
+ if (onCancelListener == null) {
+ onCancelListener = new DialogInterface.OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ dialog.dismiss();
+ }
+ };
+ }
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ final TextView title = (TextView) View.inflate(context, R.layout.dialog_title, null);
+ title.setText(R.string.dialog_new_contact_account);
+ builder.setCustomTitle(title);
+ builder.setSingleChoiceItems(accountAdapter, 0, onClickListener);
+ builder.setOnCancelListener(onCancelListener);
+ final AlertDialog result = builder.create();
+ return result;
+ }
+
+ public static void doImport(Context context, int resId, AccountWithDataSet account,
+ int subscriptionId) {
+ if (resId == R.string.import_from_sim) {
+ doImportFromSim(context, account, subscriptionId);
+ } else if (resId == R.string.import_from_vcf_file) {
+ doImportFromVcfFile(context, account);
+ }
+ }
+
+ public static void doImportFromSim(Context context, AccountWithDataSet account,
+ int subscriptionId) {
+ 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.putExtra("data_set", account.dataSet);
+ }
+ importIntent.putExtra("subscription_id", (Integer) subscriptionId);
+ importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
+ context.startActivity(importIntent);
+ }
+
+ public static void doImportFromVcfFile(Context context, AccountWithDataSet account) {
+ Intent importIntent = new Intent(context, ImportVCardActivity.class);
+ if (account != null) {
+ importIntent.putExtra("account_name", account.name);
+ importIntent.putExtra("account_type", account.type);
+ importIntent.putExtra("data_set", account.dataSet);
+ }
+
+ if (mVCardShare) {
+ importIntent.setAction(Intent.ACTION_VIEW);
+ importIntent.setData(mPath);
+ }
+ mVCardShare = false;
+ mPath = null;
+ context.startActivity(importIntent);
+ }
+}
diff --git a/src/com/android/contacts/common/util/AccountsListAdapter.java b/src/com/android/contacts/common/util/AccountsListAdapter.java
new file mode 100644
index 0000000..ef43a30
--- /dev/null
+++ b/src/com/android/contacts/common/util/AccountsListAdapter.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010 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.common.util;
+
+import android.content.Context;
+import android.text.TextUtils.TruncateAt;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * List-Adapter for Account selection
+ */
+public final class AccountsListAdapter extends BaseAdapter {
+ private final LayoutInflater mInflater;
+ private final List<AccountWithDataSet> mAccounts;
+ private final AccountTypeManager mAccountTypes;
+ private final Context mContext;
+ private int mCustomLayout = -1;
+
+ /**
+ * Filters that affect the list of accounts that is displayed by this adapter.
+ */
+ public enum AccountListFilter {
+ ALL_ACCOUNTS, // All read-only and writable accounts
+ ACCOUNTS_CONTACT_WRITABLE, // Only where the account type is contact writable
+ ACCOUNTS_GROUP_WRITABLE // Only accounts where the account type is group writable
+ }
+
+ public AccountsListAdapter(Context context, AccountListFilter accountListFilter) {
+ this(context, accountListFilter, null);
+ }
+
+ /**
+ * @param currentAccount the Account currently selected by the user, which should come
+ * first in the list. Can be null.
+ */
+ public AccountsListAdapter(Context context, AccountListFilter accountListFilter,
+ AccountWithDataSet currentAccount) {
+ mContext = context;
+ mAccountTypes = AccountTypeManager.getInstance(context);
+ mAccounts = getAccounts(accountListFilter);
+ if (currentAccount != null
+ && !mAccounts.isEmpty()
+ && !mAccounts.get(0).equals(currentAccount)
+ && mAccounts.remove(currentAccount)) {
+ mAccounts.add(0, currentAccount);
+ }
+ mInflater = LayoutInflater.from(context);
+ }
+
+ private List<AccountWithDataSet> getAccounts(AccountListFilter accountListFilter) {
+ if (accountListFilter == AccountListFilter.ACCOUNTS_GROUP_WRITABLE) {
+ return new ArrayList<AccountWithDataSet>(mAccountTypes.getGroupWritableAccounts());
+ }
+ return new ArrayList<AccountWithDataSet>(mAccountTypes.getAccounts(
+ accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE));
+ }
+
+ public void setCustomLayout(int customLayout) {
+ mCustomLayout = customLayout;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final View resultView = convertView != null ? convertView :
+ mInflater.inflate(mCustomLayout > 0 ? mCustomLayout :
+ R.layout.account_selector_list_item_condensed, parent, false);
+
+ final TextView text1 = (TextView) resultView.findViewById(android.R.id.text1);
+ final TextView text2 = (TextView) resultView.findViewById(android.R.id.text2);
+ final ImageView icon = (ImageView) resultView.findViewById(android.R.id.icon);
+
+ final AccountWithDataSet account = mAccounts.get(position);
+ final AccountType accountType = mAccountTypes.getAccountType(account.type, account.dataSet);
+
+ text1.setText(accountType.getDisplayLabel(mContext));
+ text2.setText(account.name);
+
+ icon.setImageDrawable(accountType.getDisplayIcon(mContext));
+
+ return resultView;
+ }
+
+ @Override
+ public int getCount() {
+ return mAccounts.size();
+ }
+
+ @Override
+ public AccountWithDataSet getItem(int position) {
+ return mAccounts.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+}
+
diff --git a/src/com/android/contacts/common/util/BitmapUtil.java b/src/com/android/contacts/common/util/BitmapUtil.java
new file mode 100644
index 0000000..5cd856e
--- /dev/null
+++ b/src/com/android/contacts/common/util/BitmapUtil.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.BitmapDrawable;
+
+/**
+ * Provides static functions to decode bitmaps at the optimal size
+ */
+public class BitmapUtil {
+ private BitmapUtil() {}
+
+ /**
+ * Returns Width or Height of the picture, depending on which size is smaller. Doesn't actually
+ * decode the picture, so it is pretty efficient to run.
+ */
+ public static int getSmallerExtentFromBytes(byte[] bytes) {
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+
+ // don't actually decode the picture, just return its bounds
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
+
+ // test what the best sample size is
+ return Math.min(options.outWidth, options.outHeight);
+ }
+
+ /**
+ * Finds the optimal sampleSize for loading the picture
+ * @param originalSmallerExtent Width or height of the picture, whichever is smaller
+ * @param targetExtent Width or height of the target view, whichever is bigger.
+ *
+ * If either one of the parameters is 0 or smaller, no sampling is applied
+ */
+ public static int findOptimalSampleSize(int originalSmallerExtent, int targetExtent) {
+ // If we don't know sizes, we can't do sampling.
+ if (targetExtent < 1) return 1;
+ if (originalSmallerExtent < 1) return 1;
+
+ // Test what the best sample size is. To do that, we find the sample size that gives us
+ // the best trade-off between resulting image size and memory requirement. We allow
+ // the down-sampled image to be 20% smaller than the target size. That way we can get around
+ // unfortunate cases where e.g. a 720 picture is requested for 362 and not down-sampled at
+ // all. Why 20%? Why not. Prove me wrong.
+ int extent = originalSmallerExtent;
+ int sampleSize = 1;
+ while ((extent >> 1) >= targetExtent * 0.8f) {
+ sampleSize <<= 1;
+ extent >>= 1;
+ }
+
+ return sampleSize;
+ }
+
+ /**
+ * Decodes the bitmap with the given sample size
+ */
+ public static Bitmap decodeBitmapFromBytes(byte[] bytes, int sampleSize) {
+ final BitmapFactory.Options options;
+ if (sampleSize <= 1) {
+ options = null;
+ } else {
+ options = new BitmapFactory.Options();
+ options.inSampleSize = sampleSize;
+ }
+ return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
+ }
+
+ /**
+ * Retrieves a copy of the specified drawable resource, rotated by a specified angle.
+ *
+ * @param resources The current resources.
+ * @param resourceId The resource ID of the drawable to rotate.
+ * @param angle The angle of rotation.
+ * @return Rotated drawable.
+ */
+ public static Drawable getRotatedDrawable(
+ android.content.res.Resources resources, int resourceId, float angle) {
+
+ // Get the original drawable and make a copy which will be rotated.
+ Bitmap original = BitmapFactory.decodeResource(resources, resourceId);
+ Bitmap rotated = Bitmap.createBitmap(
+ original.getWidth(), original.getHeight(), Bitmap.Config.ARGB_8888);
+
+ // Perform the rotation.
+ Canvas tempCanvas = new Canvas(rotated);
+ tempCanvas.rotate(angle, original.getWidth()/2, original.getHeight()/2);
+ tempCanvas.drawBitmap(original, 0, 0, null);
+
+ return new BitmapDrawable(resources,rotated);
+ }
+
+ /**
+ * Given an input bitmap, scales it to the given width/height and makes it round.
+ *
+ * @param input {@link Bitmap} to scale and crop
+ * @param targetWidth desired output width
+ * @param targetHeight desired output height
+ * @return output bitmap scaled to the target width/height and cropped to an oval. The
+ * cropping algorithm will try to fit as much of the input into the output as possible,
+ * while preserving the target width/height ratio.
+ */
+ public static Bitmap getRoundedBitmap(Bitmap input, int targetWidth, int targetHeight) {
+ if (input == null) {
+ return null;
+ }
+ final Bitmap.Config inputConfig = input.getConfig();
+ final Bitmap result = Bitmap.createBitmap(targetWidth, targetHeight,
+ inputConfig != null ? inputConfig : Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(result);
+ final Paint paint = new Paint();
+ canvas.drawARGB(0, 0, 0, 0);
+ paint.setAntiAlias(true);
+ final RectF dst = new RectF(0, 0, targetWidth, targetHeight);
+ canvas.drawOval(dst, paint);
+
+ // Specifies that only pixels present in the destination (i.e. the drawn oval) should
+ // be overwritten with pixels from the input bitmap.
+ paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
+
+ final int inputWidth = input.getWidth();
+ final int inputHeight = input.getHeight();
+
+ // Choose the largest scale factor that will fit inside the dimensions of the
+ // input bitmap.
+ final float scaleBy = Math.min((float) inputWidth / targetWidth,
+ (float) inputHeight / targetHeight);
+
+ final int xCropAmountHalved = (int) (scaleBy * targetWidth / 2);
+ final int yCropAmountHalved = (int) (scaleBy * targetHeight / 2);
+
+ final Rect src = new Rect(
+ inputWidth / 2 - xCropAmountHalved,
+ inputHeight / 2 - yCropAmountHalved,
+ inputWidth / 2 + xCropAmountHalved,
+ inputHeight / 2 + yCropAmountHalved);
+
+ canvas.drawBitmap(input, src, dst, paint);
+ return result;
+ }
+}
diff --git a/src/com/android/contacts/common/util/CommonDateUtils.java b/src/com/android/contacts/common/util/CommonDateUtils.java
new file mode 100644
index 0000000..bba910a
--- /dev/null
+++ b/src/com/android/contacts/common/util/CommonDateUtils.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+
+/**
+ * Common date utilities.
+ */
+public class CommonDateUtils {
+
+ // All the SimpleDateFormats in this class use the UTC timezone
+ public static final SimpleDateFormat NO_YEAR_DATE_FORMAT =
+ new SimpleDateFormat("--MM-dd", Locale.US);
+ public static final SimpleDateFormat FULL_DATE_FORMAT =
+ new SimpleDateFormat("yyyy-MM-dd", Locale.US);
+ public static final SimpleDateFormat DATE_AND_TIME_FORMAT =
+ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
+ public static final SimpleDateFormat NO_YEAR_DATE_AND_TIME_FORMAT =
+ new SimpleDateFormat("--MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
+
+ /**
+ * Exchange requires 8:00 for birthdays
+ */
+ public final static int DEFAULT_HOUR = 8;
+}
diff --git a/src/com/android/contacts/common/util/Constants.java b/src/com/android/contacts/common/util/Constants.java
new file mode 100644
index 0000000..c0d6755
--- /dev/null
+++ b/src/com/android/contacts/common/util/Constants.java
@@ -0,0 +1,29 @@
+/*
+ * 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.common.util;
+
+public class Constants {
+
+ /**
+ * Log tag for performance measurement.
+ * To enable: adb shell setprop log.tag.ContactsPerf VERBOSE
+ */
+ public static final String PERFORMANCE_TAG = "ContactsPerf";
+
+ // Used for lookup URI that contains an encoded JSON string.
+ public static final String LOOKUP_URI_ENCODED = "encoded";
+}
diff --git a/src/com/android/contacts/common/util/ContactDisplayUtils.java b/src/com/android/contacts/common/util/ContactDisplayUtils.java
new file mode 100644
index 0000000..0a50748
--- /dev/null
+++ b/src/com/android/contacts/common/util/ContactDisplayUtils.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import static android.provider.ContactsContract.CommonDataKinds.Phone;
+
+import com.google.common.base.Preconditions;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.support.annotation.Nullable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.TtsSpan;
+import android.util.Log;
+import android.util.Patterns;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
+import com.android.contacts.common.preference.ContactsPreferences;
+
+/**
+ * Methods for handling various contact data labels.
+ */
+public class ContactDisplayUtils {
+
+ private static final String TAG = ContactDisplayUtils.class.getSimpleName();
+
+ public static final int INTERACTION_CALL = 1;
+ public static final int INTERACTION_SMS = 2;
+
+ /**
+ * Checks if the given data type is a custom type.
+ *
+ * @param type Phone data type.
+ * @return {@literal true} if the type is custom. {@literal false} if not.
+ */
+ public static boolean isCustomPhoneType(Integer type) {
+ return type == Phone.TYPE_CUSTOM || type == Phone.TYPE_ASSISTANT;
+ }
+
+ /**
+ * Gets a display label for a given phone type.
+ *
+ * @param type The type of number.
+ * @param customLabel A custom label to use if the phone is determined to be of custom type
+ * determined by {@link #isCustomPhoneType(Integer))}
+ * @param interactionType whether this is a call or sms. Either {@link #INTERACTION_CALL} or
+ * {@link #INTERACTION_SMS}.
+ * @param context The application context.
+ * @return An appropriate string label
+ */
+ public static CharSequence getLabelForCallOrSms(Integer type, CharSequence customLabel,
+ int interactionType, Context context) {
+ Preconditions.checkNotNull(context);
+
+ if (isCustomPhoneType(type)) {
+ return (customLabel == null) ? "" : customLabel;
+ } else {
+ int resId;
+ if (interactionType == INTERACTION_SMS) {
+ resId = getSmsLabelResourceId(type);
+ } else {
+ resId = getPhoneLabelResourceId(type);
+ if (interactionType != INTERACTION_CALL) {
+ Log.e(TAG, "Un-recognized interaction type: " + interactionType +
+ ". Defaulting to ContactDisplayUtils.INTERACTION_CALL.");
+ }
+ }
+
+ return context.getResources().getText(resId);
+ }
+ }
+
+ /**
+ * Find a label for calling.
+ *
+ * @param type The type of number.
+ * @return An appropriate string label.
+ */
+ public static int getPhoneLabelResourceId(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;
+ }
+
+ }
+
+ /**
+ * Find a label for sending an sms.
+ *
+ * @param type The type of number.
+ * @return An appropriate string label.
+ */
+ public static int getSmsLabelResourceId(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;
+ }
+ }
+
+ /**
+ * Whether the given text could be a phone number.
+ *
+ * Note this will miss many things that are legitimate phone numbers, for example,
+ * phone numbers with letters.
+ */
+ public static boolean isPossiblePhoneNumber(CharSequence text) {
+ return text == null ? false : Patterns.PHONE.matcher(text.toString()).matches();
+ }
+
+ /**
+ * Returns a Spannable for the given message with a telephone {@link TtsSpan} set for
+ * the given phone number text wherever it is found within the message.
+ */
+ public static Spannable getTelephoneTtsSpannable(String message, String phoneNumber) {
+ if (message == null) {
+ return null;
+ }
+ final Spannable spannable = new SpannableString(message);
+ int start = phoneNumber == null ? -1 : message.indexOf(phoneNumber);
+ while (start >= 0) {
+ final int end = start + phoneNumber.length();
+ final TtsSpan ttsSpan = PhoneNumberUtilsCompat.createTtsSpan(phoneNumber);
+ spannable.setSpan(ttsSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // this is consistenly done in a misleading way..
+ start = message.indexOf(phoneNumber, end);
+ }
+ return spannable;
+ }
+
+ /**
+ * Retrieves a string from a string template that takes 1 phone number as argument,
+ * span the number with a telephone {@link TtsSpan}, and return the spanned string.
+ *
+ * @param resources to retrieve the string from
+ * @param stringId ID of the string
+ * @param number to pass in the template
+ * @return CharSequence with the phone number wrapped in a TtsSpan
+ */
+ public static CharSequence getTtsSpannedPhoneNumber(Resources resources,
+ int stringId, String number){
+ String msg = resources.getString(stringId, number);
+ return ContactDisplayUtils.getTelephoneTtsSpannable(msg, number);
+ }
+
+ /**
+ * Returns either namePrimary or nameAlternative based on the {@link ContactsPreferences}.
+ * Defaults to the name that is non-null.
+ *
+ * @param namePrimary the primary name.
+ * @param nameAlternative the alternative name.
+ * @param contactsPreferences the ContactsPreferences used to determine the preferred
+ * display name.
+ * @return namePrimary or nameAlternative depending on the value of displayOrderPreference.
+ */
+ public static String getPreferredDisplayName(String namePrimary, String nameAlternative,
+ @Nullable ContactsPreferences contactsPreferences) {
+ if (contactsPreferences == null) {
+ return namePrimary != null ? namePrimary : nameAlternative;
+ }
+ if (contactsPreferences.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
+ return namePrimary;
+ }
+
+ if (contactsPreferences.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE
+ && !TextUtils.isEmpty(nameAlternative)) {
+ return nameAlternative;
+ }
+
+ return namePrimary;
+ }
+
+ /**
+ * Returns either namePrimary or nameAlternative based on the {@link ContactsPreferences}.
+ * Defaults to the name that is non-null.
+ *
+ * @param namePrimary the primary name.
+ * @param nameAlternative the alternative name.
+ * @param contactsPreferences the ContactsPreferences used to determine the preferred sort
+ * order.
+ * @return namePrimary or nameAlternative depending on the value of displayOrderPreference.
+ */
+ public static String getPreferredSortName(String namePrimary, String nameAlternative,
+ @Nullable ContactsPreferences contactsPreferences) {
+ if (contactsPreferences == null) {
+ return namePrimary != null ? namePrimary : nameAlternative;
+ }
+
+ if (contactsPreferences.getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY) {
+ return namePrimary;
+ }
+
+ if (contactsPreferences.getSortOrder() == ContactsPreferences.SORT_ORDER_ALTERNATIVE &&
+ !TextUtils.isEmpty(nameAlternative)) {
+ return nameAlternative;
+ }
+
+ return namePrimary;
+ }
+}
diff --git a/src/com/android/contacts/common/util/ContactLoaderUtils.java b/src/com/android/contacts/common/util/ContactLoaderUtils.java
new file mode 100644
index 0000000..0ec8887
--- /dev/null
+++ b/src/com/android/contacts/common/util/ContactLoaderUtils.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 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.common.util;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.net.Uri;
+import android.provider.Contacts;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.RawContacts;
+
+/**
+ * Utility methods for the {@link ContactLoader}.
+ */
+public final class ContactLoaderUtils {
+
+ /** Static helper, not instantiable. */
+ private ContactLoaderUtils() {}
+
+ /**
+ * Transforms the given Uri and returns a Lookup-Uri that represents the contact.
+ * For legacy contacts, a raw-contact lookup is performed. An {@link IllegalArgumentException}
+ * can be thrown if the URI is null or the authority is not recognized.
+ *
+ * Do not call from the UI thread.
+ */
+ @SuppressWarnings("deprecation")
+ public static Uri ensureIsContactUri(final ContentResolver resolver, final Uri uri)
+ throws IllegalArgumentException {
+ if (uri == null) throw new IllegalArgumentException("uri must not be null");
+
+ final String authority = uri.getAuthority();
+
+ // Current Style Uri?
+ if (ContactsContract.AUTHORITY.equals(authority)) {
+ final String type = resolver.getType(uri);
+ // Contact-Uri? Good, return it
+ if (ContactsContract.Contacts.CONTENT_ITEM_TYPE.equals(type)) {
+ return uri;
+ }
+
+ // RawContact-Uri? Transform it to ContactUri
+ if (RawContacts.CONTENT_ITEM_TYPE.equals(type)) {
+ final long rawContactId = ContentUris.parseId(uri);
+ return RawContacts.getContactLookupUri(resolver,
+ ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
+ }
+
+ // Anything else? We don't know what this is
+ throw new IllegalArgumentException("uri format is unknown");
+ }
+
+ // Legacy Style? Convert to RawContact
+ final String OBSOLETE_AUTHORITY = Contacts.AUTHORITY;
+ if (OBSOLETE_AUTHORITY.equals(authority)) {
+ // Legacy Format. Convert to RawContact-Uri and then lookup the contact
+ final long rawContactId = ContentUris.parseId(uri);
+ return RawContacts.getContactLookupUri(resolver,
+ ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
+ }
+
+ throw new IllegalArgumentException("uri authority is unknown");
+ }
+}
diff --git a/src/com/android/contacts/common/util/DataStatus.java b/src/com/android/contacts/common/util/DataStatus.java
new file mode 100644
index 0000000..76f11b6
--- /dev/null
+++ b/src/com/android/contacts/common/util/DataStatus.java
@@ -0,0 +1,165 @@
+/*
+ * 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.common.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;
+
+import com.android.contacts.common.R;
+
+/**
+ * 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;
+ }
+
+ public long getTimestamp() {
+ return mTimestamp;
+ }
+
+ /**
+ * 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(
+ R.string.contact_status_update_attribution_with_date,
+ timeClause, labelClause);
+ } else if (validLabel) {
+ return context.getString(
+ 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/common/util/DateUtils.java b/src/com/android/contacts/common/util/DateUtils.java
new file mode 100644
index 0000000..c695ec6
--- /dev/null
+++ b/src/com/android/contacts/common/util/DateUtils.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2010 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.common.util;
+
+import android.content.Context;
+import android.text.format.DateFormat;
+import android.text.format.Time;
+
+
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * Utility methods for processing dates.
+ */
+public class DateUtils {
+ public static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("UTC");
+
+ /**
+ * When parsing a date without a year, the system assumes 1970, which wasn't a leap-year.
+ * Let's add a one-off hack for that day of the year
+ */
+ public static final String NO_YEAR_DATE_FEB29TH = "--02-29";
+
+ // Variations of ISO 8601 date format. Do not change the order - it does affect the
+ // result in ambiguous cases.
+ private static final SimpleDateFormat[] DATE_FORMATS = {
+ CommonDateUtils.FULL_DATE_FORMAT,
+ CommonDateUtils.DATE_AND_TIME_FORMAT,
+ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.US),
+ new SimpleDateFormat("yyyyMMdd", Locale.US),
+ new SimpleDateFormat("yyyyMMdd'T'HHmmssSSS'Z'", Locale.US),
+ new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US),
+ new SimpleDateFormat("yyyyMMdd'T'HHmm'Z'", Locale.US),
+ };
+
+ static {
+ for (SimpleDateFormat format : DATE_FORMATS) {
+ format.setLenient(true);
+ format.setTimeZone(UTC_TIMEZONE);
+ }
+ CommonDateUtils.NO_YEAR_DATE_FORMAT.setTimeZone(UTC_TIMEZONE);
+ }
+
+ /**
+ * Parses the supplied string to see if it looks like a date.
+ *
+ * @param string The string representation of the provided date
+ * @param mustContainYear If true, the string is parsed as a date containing a year. If false,
+ * the string is parsed into a valid date even if the year field is missing.
+ * @return A Calendar object corresponding to the date if the string is successfully parsed.
+ * If not, null is returned.
+ */
+ public static Calendar parseDate(String string, boolean mustContainYear) {
+ ParsePosition parsePosition = new ParsePosition(0);
+ Date date;
+ if (!mustContainYear) {
+ final boolean noYearParsed;
+ // Unfortunately, we can't parse Feb 29th correctly, so let's handle this day seperately
+ if (NO_YEAR_DATE_FEB29TH.equals(string)) {
+ return getUtcDate(0, Calendar.FEBRUARY, 29);
+ } else {
+ synchronized (CommonDateUtils.NO_YEAR_DATE_FORMAT) {
+ date = CommonDateUtils.NO_YEAR_DATE_FORMAT.parse(string, parsePosition);
+ }
+ noYearParsed = parsePosition.getIndex() == string.length();
+ }
+
+ if (noYearParsed) {
+ return getUtcDate(date, true);
+ }
+ }
+ for (int i = 0; i < DATE_FORMATS.length; i++) {
+ SimpleDateFormat f = DATE_FORMATS[i];
+ synchronized (f) {
+ parsePosition.setIndex(0);
+ date = f.parse(string, parsePosition);
+ if (parsePosition.getIndex() == string.length()) {
+ return getUtcDate(date, false);
+ }
+ }
+ }
+ return null;
+ }
+
+ private static final Calendar getUtcDate(Date date, boolean noYear) {
+ final Calendar calendar = Calendar.getInstance(UTC_TIMEZONE, Locale.US);
+ calendar.setTime(date);
+ if (noYear) {
+ calendar.set(Calendar.YEAR, 0);
+ }
+ return calendar;
+ }
+
+ private static final Calendar getUtcDate(int year, int month, int dayOfMonth) {
+ final Calendar calendar = Calendar.getInstance(UTC_TIMEZONE, Locale.US);
+ calendar.clear();
+ calendar.set(Calendar.YEAR, year);
+ calendar.set(Calendar.MONTH, month);
+ calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
+ return calendar;
+ }
+
+ public static boolean isYearSet(Calendar cal) {
+ // use the Calendar.YEAR field to track whether or not the year is set instead of
+ // Calendar.isSet() because doing Calendar.get() causes Calendar.isSet() to become
+ // true irregardless of what the previous value was
+ return cal.get(Calendar.YEAR) > 1;
+ }
+
+ /**
+ * Same as {@link #formatDate(Context context, String string, boolean longForm)}, with
+ * longForm set to {@code true} by default.
+ *
+ * @param context Valid context
+ * @param string String representation of a date to parse
+ * @return Returns the same date in a cleaned up format. If the supplied string does not look
+ * like a date, return it unchanged.
+ */
+
+ public static String formatDate(Context context, String string) {
+ return formatDate(context, string, true);
+ }
+
+ /**
+ * Parses the supplied string to see if it looks like a date.
+ *
+ * @param context Valid context
+ * @param string String representation of a date to parse
+ * @param longForm If true, return the date formatted into its long string representation.
+ * If false, return the date formatted using its short form representation (i.e. 12/11/2012)
+ * @return Returns the same date in a cleaned up format. If the supplied string does not look
+ * like a date, return it unchanged.
+ */
+ public static String formatDate(Context context, String string, boolean longForm) {
+ if (string == null) {
+ return null;
+ }
+
+ string = string.trim();
+ if (string.length() == 0) {
+ return string;
+ }
+ final Calendar cal = parseDate(string, false);
+
+ // we weren't able to parse the string successfully so just return it unchanged
+ if (cal == null) {
+ return string;
+ }
+
+ final boolean isYearSet = isYearSet(cal);
+ final java.text.DateFormat outFormat;
+ if (!isYearSet) {
+ outFormat = getLocalizedDateFormatWithoutYear(context);
+ } else {
+ outFormat =
+ longForm ? DateFormat.getLongDateFormat(context) :
+ DateFormat.getDateFormat(context);
+ }
+ synchronized (outFormat) {
+ outFormat.setTimeZone(UTC_TIMEZONE);
+ return outFormat.format(cal.getTime());
+ }
+ }
+
+ public static boolean isMonthBeforeDay(Context context) {
+ char[] dateFormatOrder = DateFormat.getDateFormatOrder(context);
+ for (int i = 0; i < dateFormatOrder.length; i++) {
+ if (dateFormatOrder[i] == 'd') {
+ return false;
+ }
+ if (dateFormatOrder[i] == 'M') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns a SimpleDateFormat object without the year fields by using a regular expression
+ * to eliminate the year in the string pattern. In the rare occurence that the resulting
+ * pattern cannot be reconverted into a SimpleDateFormat, it uses the provided context to
+ * determine whether the month field should be displayed before the day field, and returns
+ * either "MMMM dd" or "dd MMMM" converted into a SimpleDateFormat.
+ */
+ public static java.text.DateFormat getLocalizedDateFormatWithoutYear(Context context) {
+ final String pattern = ((SimpleDateFormat) SimpleDateFormat.getDateInstance(
+ java.text.DateFormat.LONG)).toPattern();
+ // Determine the correct regex pattern for year.
+ // Special case handling for Spanish locale by checking for "de"
+ final String yearPattern = pattern.contains(
+ "de") ? "[^Mm]*[Yy]+[^Mm]*" : "[^DdMm]*[Yy]+[^DdMm]*";
+ try {
+ // Eliminate the substring in pattern that matches the format for that of year
+ return new SimpleDateFormat(pattern.replaceAll(yearPattern, ""));
+ } catch (IllegalArgumentException e) {
+ return new SimpleDateFormat(
+ DateUtils.isMonthBeforeDay(context) ? "MMMM dd" : "dd MMMM");
+ }
+ }
+
+ /**
+ * Given a calendar (possibly containing only a day of the year), returns the earliest possible
+ * anniversary of the date that is equal to or after the current point in time if the date
+ * does not contain a year, or the date converted to the local time zone (if the date contains
+ * a year.
+ *
+ * @param target The date we wish to convert(in the UTC time zone).
+ * @return If date does not contain a year (year < 1900), returns the next earliest anniversary
+ * that is after the current point in time (in the local time zone). Otherwise, returns the
+ * adjusted Date in the local time zone.
+ */
+ public static Date getNextAnnualDate(Calendar target) {
+ final Calendar today = Calendar.getInstance();
+ today.setTime(new Date());
+
+ // Round the current time to the exact start of today so that when we compare
+ // today against the target date, both dates are set to exactly 0000H.
+ today.set(Calendar.HOUR_OF_DAY, 0);
+ today.set(Calendar.MINUTE, 0);
+ today.set(Calendar.SECOND, 0);
+ today.set(Calendar.MILLISECOND, 0);
+
+ final boolean isYearSet = isYearSet(target);
+ final int targetYear = target.get(Calendar.YEAR);
+ final int targetMonth = target.get(Calendar.MONTH);
+ final int targetDay = target.get(Calendar.DAY_OF_MONTH);
+ final boolean isFeb29 = (targetMonth == Calendar.FEBRUARY && targetDay == 29);
+ final GregorianCalendar anniversary = new GregorianCalendar();
+ // Convert from the UTC date to the local date. Set the year to today's year if the
+ // there is no provided year (targetYear < 1900)
+ anniversary.set(!isYearSet ? today.get(Calendar.YEAR) : targetYear,
+ targetMonth, targetDay);
+ // If the anniversary's date is before the start of today and there is no year set,
+ // increment the year by 1 so that the returned date is always equal to or greater than
+ // today. If the day is a leap year, keep going until we get the next leap year anniversary
+ // Otherwise if there is already a year set, simply return the exact date.
+ if (!isYearSet) {
+ int anniversaryYear = today.get(Calendar.YEAR);
+ if (anniversary.before(today) ||
+ (isFeb29 && !anniversary.isLeapYear(anniversaryYear))) {
+ // If the target date is not Feb 29, then set the anniversary to the next year.
+ // Otherwise, keep going until we find the next leap year (this is not guaranteed
+ // to be in 4 years time).
+ do {
+ anniversaryYear +=1;
+ } while (isFeb29 && !anniversary.isLeapYear(anniversaryYear));
+ anniversary.set(anniversaryYear, targetMonth, targetDay);
+ }
+ }
+ return anniversary.getTime();
+ }
+
+ /**
+ * Determine the difference, in days between two dates. Uses similar logic as the
+ * {@link android.text.format.DateUtils.getRelativeTimeSpanString} method.
+ *
+ * @param time Instance of time object to use for calculations.
+ * @param date1 First date to check.
+ * @param date2 Second date to check.
+ * @return The absolute difference in days between the two dates.
+ */
+ public static int getDayDifference(Time time, long date1, long date2) {
+ time.set(date1);
+ int startDay = Time.getJulianDay(date1, time.gmtoff);
+
+ time.set(date2);
+ int currentDay = Time.getJulianDay(date2, time.gmtoff);
+
+ return Math.abs(currentDay - startDay);
+ }
+}
diff --git a/src/com/android/contacts/common/util/EmptyService.java b/src/com/android/contacts/common/util/EmptyService.java
new file mode 100644
index 0000000..c5c3608
--- /dev/null
+++ b/src/com/android/contacts/common/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.common.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/common/util/ImplicitIntentsUtil.java b/src/com/android/contacts/common/util/ImplicitIntentsUtil.java
new file mode 100644
index 0000000..c6a875b
--- /dev/null
+++ b/src/com/android/contacts/common/util/ImplicitIntentsUtil.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 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.common.util;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.QuickContact;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.android.contacts.common.model.account.GoogleAccountType;
+
+import java.util.List;
+
+/**
+ * Utility for forcing intents to be started inside the current app. This is useful for avoiding
+ * senseless disambiguation dialogs. Ie, if a user clicks a contact inside Contacts we assume
+ * they want to view the contact inside the Contacts app as opposed to a 3rd party contacts app.
+ *
+ * Methods are designed to replace the use of startActivity() for implicit intents. This class isn't
+ * necessary for explicit intents. No attempt is made to replace startActivityForResult(), since
+ * startActivityForResult() is always used with explicit intents in this project.
+ *
+ * Why not just always use explicit intents? The Contacts/Dialer app implements standard intent
+ * actions used by others apps. We want to continue exercising these intent filters to make sure
+ * they still work. Plus we sometimes don't know an explicit intent would work. See
+ * {@link #startActivityInAppIfPossible}.
+ *
+ * Some ContactsCommon code that is only used by Dialer doesn't use ImplicitIntentsUtil.
+ */
+public class ImplicitIntentsUtil {
+
+ /**
+ * Start an intent. If it is possible for this app to handle the intent, force this app's
+ * activity to handle the intent. Sometimes it is impossible to know whether this app
+ * can handle an intent while coding since the code is used inside both Dialer and Contacts.
+ * This method is particularly useful in such circumstances.
+ *
+ * On a Nexus 5 with a small number of apps, this method consistently added 3-16ms of delay
+ * in order to talk to the package manager.
+ */
+ public static void startActivityInAppIfPossible(Context context, Intent intent) {
+ final Intent appIntent = getIntentInAppIfExists(context, intent);
+ if (appIntent != null) {
+ context.startActivity(appIntent);
+ } else {
+ context.startActivity(intent);
+ }
+ }
+
+ /**
+ * Start intent using an activity inside this app. This method is useful if you are certain
+ * that the intent can be handled inside this app, and you care about shaving milliseconds.
+ */
+ public static void startActivityInApp(Context context, Intent intent) {
+ String packageName = context.getPackageName();
+ intent.setPackage(packageName);
+ context.startActivity(intent);
+ }
+
+ /**
+ * Start an intent normally. Assert that the intent can't be opened inside this app.
+ */
+ public static void startActivityOutsideApp(Context context, Intent intent) {
+ final boolean isPlatformDebugBuild = Build.TYPE.equals("eng")
+ || Build.TYPE.equals("userdebug");
+ if (isPlatformDebugBuild) {
+ if (getIntentInAppIfExists(context, intent) != null) {
+ throw new AssertionError("startActivityOutsideApp() was called for an intent" +
+ " that can be handled inside the app");
+ }
+ }
+ context.startActivity(intent);
+ }
+
+ /**
+ * Returns an implicit intent for opening QuickContacts.
+ */
+ public static Intent composeQuickContactIntent(Uri contactLookupUri,
+ int extraMode) {
+ final Intent intent = new Intent(QuickContact.ACTION_QUICK_CONTACT);
+ intent.setData(contactLookupUri);
+ intent.putExtra(QuickContact.EXTRA_MODE, extraMode);
+ // Make sure not to show QuickContacts on top of another QuickContacts.
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ return intent;
+ }
+
+ /**
+ * Returns an Intent to open the Settings add account activity filtered to only
+ * display contact provider account types.
+ */
+ public static Intent getIntentForAddingAccount() {
+ final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ intent.putExtra(Settings.EXTRA_AUTHORITIES,
+ new String[]{ContactsContract.AUTHORITY});
+ return intent;
+ }
+
+ /**
+ * Returns an Intent to add a google account.
+ */
+ public static Intent getIntentForAddingGoogleAccount() {
+ final Intent intent = new Intent(Settings.ACTION_ADD_ACCOUNT);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ intent.putExtra(Settings.EXTRA_ACCOUNT_TYPES,
+ new String[]{GoogleAccountType.ACCOUNT_TYPE});
+ return intent;
+ }
+
+ /**
+ * Returns a copy of {@param intent} with a class name set, if a class inside this app
+ * has a corresponding intent filter.
+ */
+ private static Intent getIntentInAppIfExists(Context context, Intent intent) {
+ try {
+ final Intent intentCopy = new Intent(intent);
+ // Force this intentCopy to open inside the current app.
+ intentCopy.setPackage(context.getPackageName());
+ final List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(
+ intentCopy, PackageManager.MATCH_DEFAULT_ONLY);
+ if (list != null && list.size() != 0) {
+ // Now that we know the intentCopy will work inside the current app, we
+ // can return this intent non-null.
+ if (list.get(0).activityInfo != null
+ && !TextUtils.isEmpty(list.get(0).activityInfo.name)) {
+ // Now that we know the class name, we may as well attach it to intentCopy
+ // to prevent the package manager from needing to find it again inside
+ // startActivity(). This is only needed for efficiency.
+ intentCopy.setClassName(context.getPackageName(),
+ list.get(0).activityInfo.name);
+ }
+ return intentCopy;
+ }
+ return null;
+ } catch (Exception e) {
+ // Don't let the package manager crash our app. If the package manager can't resolve the
+ // intent here, then we can still call startActivity without calling setClass() first.
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/util/LocalizedNameResolver.java b/src/com/android/contacts/common/util/LocalizedNameResolver.java
new file mode 100644
index 0000000..92104c4
--- /dev/null
+++ b/src/com/android/contacts/common/util/LocalizedNameResolver.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2010 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.common.util;
+
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorDescription;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.account.ExternalAccountType;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Retrieves localized names per account type. This allows customizing texts like
+ * "All Contacts" for certain account types, but e.g. "All Friends" or "All Connections" for others.
+ */
+public class LocalizedNameResolver {
+ private static final String TAG = "LocalizedNameResolver";
+
+ private static final String CONTACTS_DATA_KIND = "ContactsDataKind";
+
+ /**
+ * Returns the name for All Contacts for the specified account type.
+ */
+ public static String getAllContactsName(Context context, String accountType) {
+ if (context == null) throw new IllegalArgumentException("Context must not be null");
+ if (accountType == null) return null;
+
+ return resolveAllContactsName(context, accountType);
+ }
+
+ /**
+ * Finds "All Contacts"-Name for the specified account type.
+ */
+ private static String resolveAllContactsName(Context context, String accountType) {
+ final AccountManager am = AccountManager.get(context);
+
+ for (AuthenticatorDescription auth : am.getAuthenticatorTypes()) {
+ if (accountType.equals(auth.type)) {
+ return resolveAllContactsNameFromMetaData(context, auth.packageName);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds the meta-data XML containing the contacts configuration and
+ * reads the picture priority from that file.
+ */
+ private static String resolveAllContactsNameFromMetaData(Context context, String packageName) {
+ final XmlResourceParser parser = ExternalAccountType.loadContactsXml(context, packageName);
+ if (parser != null) {
+ return loadAllContactsNameFromXml(context, parser, packageName);
+ }
+ return null;
+ }
+
+ private static String loadAllContactsNameFromXml(Context context, XmlPullParser parser,
+ String packageName) {
+ try {
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ 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");
+ }
+
+ final int depth = parser.getDepth();
+ while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
+ String name = parser.getName();
+ if (type == XmlPullParser.START_TAG && CONTACTS_DATA_KIND.equals(name)) {
+ final TypedArray typedArray = context.obtainStyledAttributes(attrs,
+ R.styleable.ContactsDataKind);
+ try {
+ // See if a string has been hardcoded directly into the xml
+ final String nonResourceString = typedArray.getNonResourceString(
+ R.styleable.ContactsDataKind_android_allContactsName);
+ if (nonResourceString != null) {
+ return nonResourceString;
+ }
+
+ // See if a resource is referenced. We can't rely on getString
+ // to automatically resolve it as the resource lives in a different package
+ int id = typedArray.getResourceId(
+ R.styleable.ContactsDataKind_android_allContactsName, 0);
+ if (id == 0) return null;
+
+ // Resolve the resource Id
+ final PackageManager packageManager = context.getPackageManager();
+ final Resources resources;
+ try {
+ resources = packageManager.getResourcesForApplication(packageName);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ try {
+ return resources.getString(id);
+ } catch (NotFoundException e) {
+ return null;
+ }
+ } finally {
+ typedArray.recycle();
+ }
+ }
+ }
+ return null;
+ } catch (XmlPullParserException e) {
+ throw new IllegalStateException("Problem reading XML", e);
+ } catch (IOException e) {
+ throw new IllegalStateException("Problem reading XML", e);
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/util/MaterialColorMapUtils.java b/src/com/android/contacts/common/util/MaterialColorMapUtils.java
new file mode 100644
index 0000000..a8fbf42
--- /dev/null
+++ b/src/com/android/contacts/common/util/MaterialColorMapUtils.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2014 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.common.util;
+
+import com.android.contacts.common.R;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.Trace;
+
+public class MaterialColorMapUtils {
+ private final TypedArray sPrimaryColors;
+ private final TypedArray sSecondaryColors;
+
+ public MaterialColorMapUtils(Resources resources) {
+ sPrimaryColors = resources.obtainTypedArray(
+ com.android.contacts.common.R.array.letter_tile_colors);
+ sSecondaryColors = resources.obtainTypedArray(
+ com.android.contacts.common.R.array.letter_tile_colors_dark);
+ }
+
+ public static class MaterialPalette implements Parcelable {
+ public MaterialPalette(int primaryColor, int secondaryColor) {
+ mPrimaryColor = primaryColor;
+ mSecondaryColor = secondaryColor;
+ }
+ public final int mPrimaryColor;
+ public final int mSecondaryColor;
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ MaterialPalette other = (MaterialPalette) obj;
+ if (mPrimaryColor != other.mPrimaryColor) {
+ return false;
+ }
+ if (mSecondaryColor != other.mSecondaryColor) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mPrimaryColor;
+ result = prime * result + mSecondaryColor;
+ return result;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mPrimaryColor);
+ dest.writeInt(mSecondaryColor);
+ }
+
+ private MaterialPalette(Parcel in) {
+ mPrimaryColor = in.readInt();
+ mSecondaryColor = in.readInt();
+ }
+
+ public static final Creator<MaterialPalette> CREATOR = new Creator<MaterialPalette>() {
+ @Override
+ public MaterialPalette createFromParcel(Parcel in) {
+ return new MaterialPalette(in);
+ }
+
+ @Override
+ public MaterialPalette[] newArray(int size) {
+ return new MaterialPalette[size];
+ }
+ };
+ }
+
+ /**
+ * Return primary and secondary colors from the Material color palette that are similar to
+ * {@param color}.
+ */
+ public MaterialPalette calculatePrimaryAndSecondaryColor(int color) {
+ Trace.beginSection("calculatePrimaryAndSecondaryColor");
+
+ final float colorHue = hue(color);
+ float minimumDistance = Float.MAX_VALUE;
+ int indexBestMatch = 0;
+ for (int i = 0; i < sPrimaryColors.length(); i++) {
+ final int primaryColor = sPrimaryColors.getColor(i, 0);
+ final float comparedHue = hue(primaryColor);
+ // No need to be perceptually accurate when calculating color distances since
+ // we are only mapping to 15 colors. Being slightly inaccurate isn't going to change
+ // the mapping very often.
+ final float distance = Math.abs(comparedHue - colorHue);
+ if (distance < minimumDistance) {
+ minimumDistance = distance;
+ indexBestMatch = i;
+ }
+ }
+
+ Trace.endSection();
+ return new MaterialPalette(sPrimaryColors.getColor(indexBestMatch, 0),
+ sSecondaryColors.getColor(indexBestMatch, 0));
+ }
+
+ public static MaterialPalette getDefaultPrimaryAndSecondaryColors(Resources resources) {
+ final int primaryColor = resources.getColor(
+ R.color.quickcontact_default_photo_tint_color);
+ final int secondaryColor = resources.getColor(
+ R.color.quickcontact_default_photo_tint_color_dark);
+ return new MaterialPalette(primaryColor, secondaryColor);
+ }
+
+ /**
+ * Returns the hue component of a color int.
+ *
+ * @return A value between 0.0f and 1.0f
+ */
+ public static float hue(int color) {
+ int r = (color >> 16) & 0xFF;
+ int g = (color >> 8) & 0xFF;
+ int b = color & 0xFF;
+
+ int V = Math.max(b, Math.max(r, g));
+ int temp = Math.min(b, Math.min(r, g));
+
+ float H;
+
+ if (V == temp) {
+ H = 0;
+ } else {
+ final float vtemp = V - temp;
+ final float cr = (V - r) / vtemp;
+ final float cg = (V - g) / vtemp;
+ final float cb = (V - b) / vtemp;
+
+ if (r == V) {
+ H = cb - cg;
+ } else if (g == V) {
+ H = 2 + cr - cb;
+ } else {
+ H = 4 + cg - cr;
+ }
+
+ H /= 6.f;
+ if (H < 0) {
+ H++;
+ }
+ }
+
+ return H;
+ }
+}
diff --git a/src/com/android/contacts/common/util/NameConverter.java b/src/com/android/contacts/common/util/NameConverter.java
new file mode 100644
index 0000000..9706353
--- /dev/null
+++ b/src/com/android/contacts/common/util/NameConverter.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2011 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.common.util;
+
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.net.Uri.Builder;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.text.TextUtils;
+
+import com.android.contacts.common.model.dataitem.StructuredNameDataItem;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Utility class for converting between a display name and structured name (and vice-versa), via
+ * calls to the contact provider.
+ */
+public class NameConverter {
+
+ /**
+ * The array of fields that comprise a structured name.
+ */
+ public static final String[] STRUCTURED_NAME_FIELDS = new String[] {
+ StructuredName.PREFIX,
+ StructuredName.GIVEN_NAME,
+ StructuredName.MIDDLE_NAME,
+ StructuredName.FAMILY_NAME,
+ StructuredName.SUFFIX
+ };
+
+ /**
+ * Converts the given structured name (provided as a map from {@link StructuredName} fields to
+ * corresponding values) into a display name string.
+ * <p>
+ * Note that this operates via a call back to the ContactProvider, but it does not access the
+ * database, so it should be safe to call from the UI thread. See
+ * ContactsProvider2.completeName() for the underlying method call.
+ * @param context Activity context.
+ * @param structuredName The structured name map to convert.
+ * @return The display name computed from the structured name map.
+ */
+ public static String structuredNameToDisplayName(Context context,
+ Map<String, String> structuredName) {
+ Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name");
+ for (String key : STRUCTURED_NAME_FIELDS) {
+ if (structuredName.containsKey(key)) {
+ appendQueryParameter(builder, key, structuredName.get(key));
+ }
+ }
+ return fetchDisplayName(context, builder.build());
+ }
+
+ /**
+ * Converts the given structured name (provided as ContentValues) into a display name string.
+ * @param context Activity context.
+ * @param values The content values containing values comprising the structured name.
+ * @return
+ */
+ public static String structuredNameToDisplayName(Context context, ContentValues values) {
+ Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name");
+ for (String key : STRUCTURED_NAME_FIELDS) {
+ if (values.containsKey(key)) {
+ appendQueryParameter(builder, key, values.getAsString(key));
+ }
+ }
+ return fetchDisplayName(context, builder.build());
+ }
+
+ /**
+ * Helper method for fetching the display name via the given URI.
+ */
+ private static String fetchDisplayName(Context context, Uri uri) {
+ String displayName = null;
+ Cursor cursor = context.getContentResolver().query(uri, new String[]{
+ StructuredName.DISPLAY_NAME,
+ }, null, null, null);
+
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ displayName = cursor.getString(0);
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ return displayName;
+ }
+
+ /**
+ * Converts the given display name string into a structured name (as a map from
+ * {@link StructuredName} fields to corresponding values).
+ * <p>
+ * Note that this operates via a call back to the ContactProvider, but it does not access the
+ * database, so it should be safe to call from the UI thread.
+ * @param context Activity context.
+ * @param displayName The display name to convert.
+ * @return The structured name map computed from the display name.
+ */
+ public static Map<String, String> displayNameToStructuredName(Context context,
+ String displayName) {
+ Map<String, String> structuredName = new TreeMap<String, String>();
+ Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name");
+
+ appendQueryParameter(builder, StructuredName.DISPLAY_NAME, displayName);
+ Cursor cursor = context.getContentResolver().query(builder.build(), STRUCTURED_NAME_FIELDS,
+ null, null, null);
+
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ for (int i = 0; i < STRUCTURED_NAME_FIELDS.length; i++) {
+ structuredName.put(STRUCTURED_NAME_FIELDS[i], cursor.getString(i));
+ }
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ return structuredName;
+ }
+
+ /**
+ * Converts the given display name string into a structured name (inserting the structured
+ * values into a new or existing ContentValues object).
+ * <p>
+ * Note that this operates via a call back to the ContactProvider, but it does not access the
+ * database, so it should be safe to call from the UI thread.
+ * @param context Activity context.
+ * @param displayName The display name to convert.
+ * @param contentValues The content values object to place the structured name values into. If
+ * null, a new one will be created and returned.
+ * @return The ContentValues object containing the structured name fields derived from the
+ * display name.
+ */
+ public static ContentValues displayNameToStructuredName(Context context, String displayName,
+ ContentValues contentValues) {
+ if (contentValues == null) {
+ contentValues = new ContentValues();
+ }
+ Map<String, String> mapValues = displayNameToStructuredName(context, displayName);
+ for (String key : mapValues.keySet()) {
+ contentValues.put(key, mapValues.get(key));
+ }
+ return contentValues;
+ }
+
+ private static void appendQueryParameter(Builder builder, String field, String value) {
+ if (!TextUtils.isEmpty(value)) {
+ builder.appendQueryParameter(field, value);
+ }
+ }
+
+ /**
+ * Parses phonetic name and returns parsed data (family, middle, given) as ContentValues.
+ * Parsed data should be {@link StructuredName#PHONETIC_FAMILY_NAME},
+ * {@link StructuredName#PHONETIC_MIDDLE_NAME}, and
+ * {@link StructuredName#PHONETIC_GIVEN_NAME}.
+ * If this method cannot parse given phoneticName, null values will be stored.
+ *
+ * @param phoneticName Phonetic name to be parsed
+ * @param values ContentValues to be used for storing data. If null, new instance will be
+ * created.
+ * @return ContentValues with parsed data. Those data can be null.
+ */
+ public static StructuredNameDataItem parsePhoneticName(String phoneticName,
+ StructuredNameDataItem item) {
+ String family = null;
+ String middle = null;
+ String given = null;
+
+ if (!TextUtils.isEmpty(phoneticName)) {
+ String[] strings = phoneticName.split(" ", 3);
+ switch (strings.length) {
+ case 1:
+ family = strings[0];
+ break;
+ case 2:
+ family = strings[0];
+ given = strings[1];
+ break;
+ case 3:
+ family = strings[0];
+ middle = strings[1];
+ given = strings[2];
+ break;
+ }
+ }
+
+ if (item == null) {
+ item = new StructuredNameDataItem();
+ }
+ item.setPhoneticFamilyName(family);
+ item.setPhoneticMiddleName(middle);
+ item.setPhoneticGivenName(given);
+ return item;
+ }
+
+ /**
+ * Constructs and returns a phonetic full name from given parts.
+ */
+ public static String buildPhoneticName(String family, String middle, String given) {
+ if (!TextUtils.isEmpty(family) || !TextUtils.isEmpty(middle)
+ || !TextUtils.isEmpty(given)) {
+ StringBuilder sb = new StringBuilder();
+ if (!TextUtils.isEmpty(family)) {
+ sb.append(family.trim()).append(' ');
+ }
+ if (!TextUtils.isEmpty(middle)) {
+ sb.append(middle.trim()).append(' ');
+ }
+ if (!TextUtils.isEmpty(given)) {
+ sb.append(given.trim()).append(' ');
+ }
+ sb.setLength(sb.length() - 1); // Yank the last space
+ return sb.toString();
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/util/PermissionsUtil.java b/src/com/android/contacts/common/util/PermissionsUtil.java
new file mode 100644
index 0000000..37c1762
--- /dev/null
+++ b/src/com/android/contacts/common/util/PermissionsUtil.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 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.common.util;
+
+import android.Manifest.permission;
+import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.content.LocalBroadcastManager;
+
+/**
+ * Utility class to help with runtime permissions.
+ */
+public class PermissionsUtil {
+ // Each permission in this list is a cherry-picked permission from a particular permission
+ // group. Granting a permission group enables access to all permissions in that group so we
+ // only need to check a single permission in each group.
+ // Note: This assumes that the app has correctly requested for all the relevant permissions
+ // in its Manifest file.
+ public static final String PHONE = permission.CALL_PHONE;
+ public static final String CONTACTS = permission.READ_CONTACTS;
+ public static final String LOCATION = permission.ACCESS_FINE_LOCATION;
+
+ public static boolean hasPhonePermissions(Context context) {
+ return hasPermission(context, PHONE);
+ }
+
+ public static boolean hasContactsPermissions(Context context) {
+ return hasPermission(context, CONTACTS);
+ }
+
+ public static boolean hasLocationPermissions(Context context) {
+ return hasPermission(context, LOCATION);
+ }
+
+ public static boolean hasPermission(Context context, String permission) {
+ return ContextCompat.checkSelfPermission(context, permission)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ public static boolean hasAppOp(Context context, String appOp) {
+ final AppOpsManager appOpsManager =
+ (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ final int mode = appOpsManager.checkOpNoThrow(appOp, Process.myUid(),
+ context.getPackageName());
+ return mode == AppOpsManager.MODE_ALLOWED;
+ }
+
+ /**
+ * Rudimentary methods wrapping the use of a LocalBroadcastManager to simplify the process
+ * of notifying other classes when a particular fragment is notified that a permission is
+ * granted.
+ *
+ * To be notified when a permission has been granted, create a new broadcast receiver
+ * and register it using {@link #registerPermissionReceiver(Context, BroadcastReceiver, String)}
+ *
+ * E.g.
+ *
+ * final BroadcastReceiver receiver = new BroadcastReceiver() {
+ * @Override
+ * public void onReceive(Context context, Intent intent) {
+ * refreshContactsView();
+ * }
+ * }
+ *
+ * PermissionsUtil.registerPermissionReceiver(getActivity(), receiver, READ_CONTACTS);
+ *
+ * If you register to listen for multiple permissions, you can identify which permission was
+ * granted by inspecting {@link Intent#getAction()}.
+ *
+ * In the fragment that requests for the permission, be sure to call
+ * {@link #notifyPermissionGranted(Context, String)} when the permission is granted so that
+ * any interested listeners are notified of the change.
+ */
+ public static void registerPermissionReceiver(Context context, BroadcastReceiver receiver,
+ String permission) {
+ final IntentFilter filter = new IntentFilter(permission);
+ LocalBroadcastManager.getInstance(context).registerReceiver(receiver, filter);
+ }
+
+ public static void unregisterPermissionReceiver(Context context, BroadcastReceiver receiver) {
+ LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver);
+ }
+
+ public static void notifyPermissionGranted(Context context, String permission) {
+ final Intent intent = new Intent(permission);
+ LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
+ }
+}
diff --git a/src/com/android/contacts/common/util/PhoneNumberFormatter.java b/src/com/android/contacts/common/util/PhoneNumberFormatter.java
new file mode 100644
index 0000000..bbf9785
--- /dev/null
+++ b/src/com/android/contacts/common/util/PhoneNumberFormatter.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2011 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.common.util;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.telephony.PhoneNumberFormattingTextWatcher;
+import android.widget.TextView;
+
+import com.android.contacts.common.GeoUtil;
+import com.android.contacts.common.compat.PhoneNumberFormattingTextWatcherCompat;
+
+public final class PhoneNumberFormatter {
+ private PhoneNumberFormatter() {}
+
+ /**
+ * Load {@link TextWatcherLoadAsyncTask} in a worker thread and set it to a {@link TextView}.
+ */
+ private static class TextWatcherLoadAsyncTask extends
+ AsyncTask<Void, Void, PhoneNumberFormattingTextWatcher> {
+ private final String mCountryCode;
+ private final TextView mTextView;
+ private final boolean mFormatAfterWatcherSet;
+
+ public TextWatcherLoadAsyncTask(
+ String countryCode, TextView textView, boolean formatAfterWatcherSet) {
+ mCountryCode = countryCode;
+ mTextView = textView;
+ mFormatAfterWatcherSet = formatAfterWatcherSet;
+ }
+
+ @Override
+ protected PhoneNumberFormattingTextWatcher doInBackground(Void... params) {
+ return PhoneNumberFormattingTextWatcherCompat.newInstance(mCountryCode);
+ }
+
+ @Override
+ protected void onPostExecute(PhoneNumberFormattingTextWatcher watcher) {
+ if (watcher == null || isCancelled()) {
+ return; // May happen if we cancel the task.
+ }
+
+ // Setting a text changed listener is safe even after the view is detached.
+ mTextView.addTextChangedListener(watcher);
+
+ // Forcing formatting the existing phone number
+ if (mFormatAfterWatcherSet) {
+ watcher.afterTextChanged(mTextView.getEditableText());
+ }
+ }
+ }
+
+ /**
+ * Delay-set {@link PhoneNumberFormattingTextWatcher} to a {@link TextView}.
+ */
+ public static final void setPhoneNumberFormattingTextWatcher(Context context,
+ TextView textView) {
+ setPhoneNumberFormattingTextWatcher(context, textView,
+ /* formatAfterWatcherSet =*/ false);
+ }
+
+ /**
+ * Delay-sets {@link PhoneNumberFormattingTextWatcher} to a {@link TextView}
+ * and formats the number immediately if formatAfterWaterSet is true.
+ * In some cases, formatting before user editing might cause unwanted results
+ * (e.g. the editor thinks the user changed the content, and would save
+ * when closed even when the user didn't make other changes.)
+ */
+ public static final void setPhoneNumberFormattingTextWatcher(
+ Context context, TextView textView, boolean formatAfterWatcherSet) {
+ new TextWatcherLoadAsyncTask(GeoUtil.getCurrentCountryIso(context),
+ textView, formatAfterWatcherSet)
+ .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ }
+}
diff --git a/src/com/android/contacts/common/util/PhoneNumberHelper.java b/src/com/android/contacts/common/util/PhoneNumberHelper.java
new file mode 100644
index 0000000..794b6dd
--- /dev/null
+++ b/src/com/android/contacts/common/util/PhoneNumberHelper.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2013 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.common.util;
+
+import android.content.Context;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+import com.google.i18n.phonenumbers.ShortNumberInfo;
+
+import java.util.Locale;
+
+/**
+ * This class wraps several PhoneNumberUtil calls and TelephonyManager calls. Some of them are
+ * the same as the ones in the framework's code base. We can remove those once they are part of
+ * the public API.
+ */
+public class PhoneNumberHelper {
+
+ private static final String LOG_TAG = PhoneNumberHelper.class.getSimpleName();
+
+ private static final String KOREA_ISO_COUNTRY_CODE = "KR";
+ /**
+ * Determines if the specified number is actually a URI (i.e. a SIP address) rather than a
+ * regular PSTN phone number, based on whether or not the number contains an "@" character.
+ *
+ * @param number Phone number
+ * @return true if number contains @
+ *
+ * TODO: Remove if PhoneNumberUtils.isUriNumber(String number) is made public.
+ */
+ public static boolean isUriNumber(String number) {
+ // Note we allow either "@" or "%40" to indicate a URI, in case
+ // the passed-in string is URI-escaped. (Neither "@" nor "%40"
+ // will ever be found in a legal PSTN number.)
+ return number != null && (number.contains("@") || number.contains("%40"));
+ }
+
+ /**
+ * Normalize a phone number by removing the characters other than digits. If
+ * the given number has keypad letters, the letters will be converted to
+ * digits first.
+ *
+ * @param phoneNumber The number to be normalized.
+ * @return The normalized number.
+ *
+ * TODO: Remove if PhoneNumberUtils.normalizeNumber(String phoneNumber) is made public.
+ */
+ public static String normalizeNumber(String phoneNumber) {
+ StringBuilder sb = new StringBuilder();
+ int len = phoneNumber.length();
+ for (int i = 0; i < len; i++) {
+ char c = phoneNumber.charAt(i);
+ // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
+ int digit = Character.digit(c, 10);
+ if (digit != -1) {
+ sb.append(digit);
+ } else if (i == 0 && c == '+') {
+ sb.append(c);
+ } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ return normalizeNumber(PhoneNumberUtils.convertKeypadLettersToDigits(phoneNumber));
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * @return the "username" part of the specified SIP address, i.e. the part before the "@"
+ * character (or "%40").
+ *
+ * @param number SIP address of the form "username@domainname" (or the URI-escaped equivalent
+ * "username%40domainname")
+ *
+ * TODO: Remove if PhoneNumberUtils.getUsernameFromUriNumber(String number) is made public.
+ */
+ public static String getUsernameFromUriNumber(String number) {
+ // The delimiter between username and domain name can be
+ // either "@" or "%40" (the URI-escaped equivalent.)
+ int delimiterIndex = number.indexOf('@');
+ if (delimiterIndex < 0) {
+ delimiterIndex = number.indexOf("%40");
+ }
+ if (delimiterIndex < 0) {
+ Log.w(LOG_TAG,
+ "getUsernameFromUriNumber: no delimiter found in SIP addr '" + number + "'");
+ return number;
+ }
+ return number.substring(0, delimiterIndex);
+ }
+}
diff --git a/src/com/android/contacts/common/util/SchedulingUtils.java b/src/com/android/contacts/common/util/SchedulingUtils.java
new file mode 100644
index 0000000..1dfa153
--- /dev/null
+++ b/src/com/android/contacts/common/util/SchedulingUtils.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import android.view.View;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+
+/** Static methods that are useful for scheduling actions to occur at a later time. */
+public class SchedulingUtils {
+
+
+ /** Runs a piece of code after the next layout run */
+ public static void doAfterLayout(final View view, final Runnable runnable) {
+ final OnGlobalLayoutListener listener = new OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ // Layout pass done, unregister for further events
+ view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ runnable.run();
+ }
+ };
+ view.getViewTreeObserver().addOnGlobalLayoutListener(listener);
+ }
+
+ /** Runs a piece of code just before the next draw, after layout and measurement */
+ public static void doOnPreDraw(final View view, final boolean drawNextFrame,
+ final Runnable runnable) {
+ final OnPreDrawListener listener = new OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ view.getViewTreeObserver().removeOnPreDrawListener(this);
+ runnable.run();
+ return drawNextFrame;
+ }
+ };
+ view.getViewTreeObserver().addOnPreDrawListener(listener);
+ }
+}
diff --git a/src/com/android/contacts/common/util/SearchUtil.java b/src/com/android/contacts/common/util/SearchUtil.java
new file mode 100644
index 0000000..ed41d6c
--- /dev/null
+++ b/src/com/android/contacts/common/util/SearchUtil.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Methods related to search.
+ */
+public class SearchUtil {
+
+ public static class MatchedLine {
+
+ public int startIndex = -1;
+ public String line;
+
+ @Override
+ public String toString() {
+ return "MatchedLine{" +
+ "line='" + line + '\'' +
+ ", startIndex=" + startIndex +
+ '}';
+ }
+ }
+
+ /**
+ * Given a string with lines delimited with '\n', finds the matching line to the given
+ * substring.
+ *
+ * @param contents The string to search.
+ * @param substring The substring to search for.
+ * @return A MatchedLine object containing the matching line and the startIndex of the substring
+ * match within that line.
+ */
+ public static MatchedLine findMatchingLine(String contents, String substring) {
+ final MatchedLine matched = new MatchedLine();
+
+ // Snippet may contain multiple lines separated by "\n".
+ // Locate the lines of the content that contain the substring.
+ final int index = SearchUtil.contains(contents, substring);
+ if (index != -1) {
+ // Match found. Find the corresponding line.
+ int start = index - 1;
+ while (start > -1) {
+ if (contents.charAt(start) == '\n') {
+ break;
+ }
+ start--;
+ }
+ int end = index + 1;
+ while (end < contents.length()) {
+ if (contents.charAt(end) == '\n') {
+ break;
+ }
+ end++;
+ }
+ matched.line = contents.substring(start + 1, end);
+ matched.startIndex = index - (start + 1);
+ }
+ return matched;
+ }
+
+ /**
+ * Similar to String.contains() with two main differences:
+ * <p>
+ * 1) Only searches token prefixes. A token is defined as any combination of letters or
+ * numbers.
+ * <p>
+ * 2) Returns the starting index where the substring is found.
+ *
+ * @param value The string to search.
+ * @param substring The substring to look for.
+ * @return The starting index where the substring is found. {@literal -1} if substring is not
+ * found in value.
+ */
+ @VisibleForTesting
+ static int contains(String value, String substring) {
+ if (value.length() < substring.length()) {
+ return -1;
+ }
+
+ // i18n support
+ // Generate the code points for the substring once.
+ // There will be a maximum of substring.length code points. But may be fewer.
+ // Since the array length is not an accurate size, we need to keep a separate variable.
+ final int[] substringCodePoints = new int[substring.length()];
+ int substringLength = 0; // may not equal substring.length()!!
+ for (int i = 0; i < substring.length(); ) {
+ final int codePoint = Character.codePointAt(substring, i);
+ substringCodePoints[substringLength] = codePoint;
+ substringLength++;
+ i += Character.charCount(codePoint);
+ }
+
+ for (int i = 0; i < value.length(); i = findNextTokenStart(value, i)) {
+ int numMatch = 0;
+ for (int j = i; j < value.length() && numMatch < substringLength; ++numMatch) {
+ int valueCp = Character.toLowerCase(value.codePointAt(j));
+ int substringCp = substringCodePoints[numMatch];
+ if (valueCp != substringCp) {
+ break;
+ }
+ j += Character.charCount(valueCp);
+ }
+ if (numMatch == substringLength) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Find the start of the next token. A token is composed of letters and numbers. Any other
+ * character are considered delimiters.
+ *
+ * @param line The string to search for the next token.
+ * @param startIndex The index to start searching. 0 based indexing.
+ * @return The index for the start of the next token. line.length() if next token not found.
+ */
+ @VisibleForTesting
+ static int findNextTokenStart(String line, int startIndex) {
+ int index = startIndex;
+
+ // If already in token, eat remainder of token.
+ while (index <= line.length()) {
+ if (index == line.length()) {
+ // No more tokens.
+ return index;
+ }
+ final int codePoint = line.codePointAt(index);
+ if (!Character.isLetterOrDigit(codePoint)) {
+ break;
+ }
+ index += Character.charCount(codePoint);
+ }
+
+ // Out of token, eat all consecutive delimiters.
+ while (index <= line.length()) {
+ if (index == line.length()) {
+ return index;
+ }
+ final int codePoint = line.codePointAt(index);
+ if (Character.isLetterOrDigit(codePoint)) {
+ break;
+ }
+ index += Character.charCount(codePoint);
+ }
+
+ return index;
+ }
+
+ /**
+ * Anything other than letter and numbers are considered delimiters. Remove start and end
+ * delimiters since they are not relevant to search.
+ *
+ * @param query The query string to clean.
+ * @return The cleaned query. Empty string if all characters are cleaned out.
+ */
+ public static String cleanStartAndEndOfSearchQuery(String query) {
+ int start = 0;
+ while (start < query.length()) {
+ int codePoint = query.codePointAt(start);
+ if (Character.isLetterOrDigit(codePoint)) {
+ break;
+ }
+ start += Character.charCount(codePoint);
+ }
+
+ if (start == query.length()) {
+ // All characters are delimiters.
+ return "";
+ }
+
+ int end = query.length() - 1;
+ while (end > -1) {
+ if (Character.isLowSurrogate(query.charAt(end))) {
+ // Assume valid i18n string. There should be a matching high surrogate before it.
+ end--;
+ }
+ int codePoint = query.codePointAt(end);
+ if (Character.isLetterOrDigit(codePoint)) {
+ break;
+ }
+ end--;
+ }
+
+ // end is a letter or digit.
+ return query.substring(start, end + 1);
+ }
+}
diff --git a/src/com/android/contacts/common/util/StopWatch.java b/src/com/android/contacts/common/util/StopWatch.java
new file mode 100644
index 0000000..581d6ee
--- /dev/null
+++ b/src/com/android/contacts/common/util/StopWatch.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import android.util.Log;
+
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+
+/**
+ * A {@link StopWatch} records start, laps and stop, and print them to logcat.
+ */
+public class StopWatch {
+
+ private final String mLabel;
+
+ private final ArrayList<Long> mTimes = Lists.newArrayList();
+ private final ArrayList<String> mLapLabels = Lists.newArrayList();
+
+ private StopWatch(String label) {
+ mLabel = label;
+ lap("");
+ }
+
+ /**
+ * Create a new instance and start it.
+ */
+ public static StopWatch start(String label) {
+ return new StopWatch(label);
+ }
+
+ /**
+ * Record a lap.
+ */
+ public void lap(String lapLabel) {
+ mTimes.add(System.currentTimeMillis());
+ mLapLabels.add(lapLabel);
+ }
+
+ /**
+ * Stop it and log the result, if the total time >= {@code timeThresholdToLog}.
+ */
+ public void stopAndLog(String TAG, int timeThresholdToLog) {
+
+ lap("");
+
+ final long start = mTimes.get(0);
+ final long stop = mTimes.get(mTimes.size() - 1);
+
+ final long total = stop - start;
+ if (total < timeThresholdToLog) return;
+
+ final StringBuilder sb = new StringBuilder();
+ sb.append(mLabel);
+ sb.append(",");
+ sb.append(total);
+ sb.append(": ");
+
+ long last = start;
+ for (int i = 1; i < mTimes.size(); i++) {
+ final long current = mTimes.get(i);
+ sb.append(mLapLabels.get(i));
+ sb.append(",");
+ sb.append((current - last));
+ sb.append(" ");
+ last = current;
+ }
+ Log.v(TAG, sb.toString());
+ }
+
+ /**
+ * Return a dummy instance that does no operations.
+ */
+ public static StopWatch getNullStopWatch() {
+ return NullStopWatch.INSTANCE;
+ }
+
+ private static class NullStopWatch extends StopWatch {
+ public static final NullStopWatch INSTANCE = new NullStopWatch();
+
+ public NullStopWatch() {
+ super(null);
+ }
+
+ @Override
+ public void lap(String lapLabel) {
+ // noop
+ }
+
+ @Override
+ public void stopAndLog(String TAG, int timeThresholdToLog) {
+ // noop
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/util/TelephonyManagerUtils.java b/src/com/android/contacts/common/util/TelephonyManagerUtils.java
new file mode 100644
index 0000000..7c322ca
--- /dev/null
+++ b/src/com/android/contacts/common/util/TelephonyManagerUtils.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 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.common.util;
+
+import android.content.Context;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.Locale;
+
+/**
+ * This class provides several TelephonyManager util functions.
+ */
+public class TelephonyManagerUtils {
+
+ private static final String LOG_TAG = TelephonyManagerUtils.class.getSimpleName();
+
+ /**
+ * Gets the voicemail tag from Telephony Manager.
+ * @param context Current application context
+ * @return Voicemail tag, the alphabetic identifier associated with the voice mail number.
+ */
+ public static String getVoiceMailAlphaTag(Context context) {
+ final TelephonyManager telephonyManager =
+ (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+ final String voiceMailLabel = telephonyManager.getVoiceMailAlphaTag();
+ return voiceMailLabel;
+ }
+
+ /**
+ * @return The ISO 3166-1 two letters country code of the country the user
+ * is in based on the network location. If the network location does not exist, fall
+ * back to the locale setting.
+ */
+ public static String getCurrentCountryIso(Context context, Locale locale) {
+ // Without framework function calls, this seems to be the most accurate location service
+ // we can rely on.
+ final TelephonyManager telephonyManager =
+ (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+ String countryIso = telephonyManager.getNetworkCountryIso().toUpperCase();
+
+ if (countryIso == null) {
+ countryIso = locale.getCountry();
+ Log.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
+ + countryIso);
+ }
+ return countryIso;
+ }
+
+ /**
+ * @param context Current application context.
+ * @return True if there is a subscription which supports video calls. False otherwise.
+ */
+ public static boolean hasVideoCallSubscription(Context context) {
+ // TODO: Check the telephony manager's subscriptions to see if any support video calls.
+ return true;
+ }
+}
diff --git a/src/com/android/contacts/common/util/TrafficStatsTags.java b/src/com/android/contacts/common/util/TrafficStatsTags.java
new file mode 100644
index 0000000..78faa94
--- /dev/null
+++ b/src/com/android/contacts/common/util/TrafficStatsTags.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 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.common.util;
+
+public class TrafficStatsTags {
+ public static final int CONTACT_PHOTO_DOWNLOAD_TAG = 0x0001;
+ public static final int TAG_MAX = 0x9999;
+}
diff --git a/src/com/android/contacts/common/util/UriUtils.java b/src/com/android/contacts/common/util/UriUtils.java
new file mode 100644
index 0000000..41ef62f
--- /dev/null
+++ b/src/com/android/contacts/common/util/UriUtils.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2011 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.common.util;
+
+import android.net.Uri;
+import android.provider.ContactsContract;
+
+import java.util.List;
+
+/**
+ * Utility methods for dealing with URIs.
+ */
+public class UriUtils {
+ /** Static helper, not instantiable. */
+ private UriUtils() {}
+
+ /** Checks whether two URI are equal, taking care of the case where either is null. */
+ public static boolean areEqual(Uri uri1, Uri uri2) {
+ if (uri1 == null && uri2 == null) {
+ return true;
+ }
+ if (uri1 == null || uri2 == null) {
+ return false;
+ }
+ return uri1.equals(uri2);
+ }
+
+ /** Parses a string into a URI and returns null if the given string is null. */
+ public static Uri parseUriOrNull(String uriString) {
+ if (uriString == null) {
+ return null;
+ }
+ return Uri.parse(uriString);
+ }
+
+ /** Converts a URI into a string, returns null if the given URI is null. */
+ public static String uriToString(Uri uri) {
+ return uri == null ? null : uri.toString();
+ }
+
+ public static boolean isEncodedContactUri(Uri uri) {
+ if (uri == null) {
+ return false;
+ }
+ final String lastPathSegment = uri.getLastPathSegment();
+ if (lastPathSegment == null) {
+ return false;
+ }
+ return lastPathSegment.equals(Constants.LOOKUP_URI_ENCODED);
+ }
+
+ /**
+ * @return {@code uri} as-is if the authority is of contacts provider. Otherwise
+ * or {@code uri} is null, return null otherwise
+ */
+ public static Uri nullForNonContactsUri(Uri uri) {
+ if (uri == null) {
+ return null;
+ }
+ return ContactsContract.AUTHORITY.equals(uri.getAuthority()) ? uri : null;
+ }
+
+ /**
+ * Parses the given URI to determine the original lookup key of the contact.
+ */
+ public static String getLookupKeyFromUri(Uri lookupUri) {
+ // Would be nice to be able to persist the lookup key somehow to avoid having to parse
+ // the uri entirely just to retrieve the lookup key, but every uri is already parsed
+ // once anyway to check if it is an encoded JSON uri, so this has negligible effect
+ // on performance.
+ if (lookupUri != null && !UriUtils.isEncodedContactUri(lookupUri)) {
+ final List<String> segments = lookupUri.getPathSegments();
+ // This returns the third path segment of the uri, where the lookup key is located.
+ // See {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
+ return (segments.size() < 3) ? null : Uri.encode(segments.get(2));
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/util/ViewUtil.java b/src/com/android/contacts/common/util/ViewUtil.java
new file mode 100644
index 0000000..895b757
--- /dev/null
+++ b/src/com/android/contacts/common/util/ViewUtil.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import android.content.res.Resources;
+import android.graphics.Outline;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.widget.ListView;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.CompatUtils;
+
+/**
+ * Provides static functions to work with views
+ */
+public class ViewUtil {
+ private ViewUtil() {}
+
+ /**
+ * Returns the width as specified in the LayoutParams
+ * @throws IllegalStateException Thrown if the view's width is unknown before a layout pass
+ * s
+ */
+ public static int getConstantPreLayoutWidth(View view) {
+ // We haven't been layed out yet, so get the size from the LayoutParams
+ final ViewGroup.LayoutParams p = view.getLayoutParams();
+ if (p.width < 0) {
+ throw new IllegalStateException("Expecting view's width to be a constant rather " +
+ "than a result of the layout pass");
+ }
+ return p.width;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not the view's layout direction is RTL
+ *
+ * @param view - A valid view
+ * @return True if the view's layout direction is RTL
+ */
+ public static boolean isViewLayoutRtl(View view) {
+ return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ }
+
+ private static final ViewOutlineProvider OVAL_OUTLINE_PROVIDER;
+ static {
+ if (CompatUtils.isLollipopCompatible()) {
+ OVAL_OUTLINE_PROVIDER = new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setOval(0, 0, view.getWidth(), view.getHeight());
+ }
+ };
+ } else {
+ OVAL_OUTLINE_PROVIDER = null;
+ }
+ }
+
+ private static final ViewOutlineProvider RECT_OUTLINE_PROVIDER;
+ static {
+ if (CompatUtils.isLollipopCompatible()) {
+ RECT_OUTLINE_PROVIDER = new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRect(0, 0, view.getWidth(), view.getHeight());
+ }
+ };
+ } else {
+ RECT_OUTLINE_PROVIDER = null;
+ }
+ }
+
+ /**
+ * Adds a rectangular outline to a view. This can be useful when you want to add a shadow
+ * to a transparent view. See b/16856049.
+ * @param view view that the outline is added to
+ * @param res The resources file.
+ */
+ public static void addRectangularOutlineProvider(View view, Resources res) {
+ if (CompatUtils.isLollipopCompatible()) {
+ view.setOutlineProvider(RECT_OUTLINE_PROVIDER);
+ }
+ }
+
+ /**
+ * Configures the floating action button, clipping it to a circle and setting its translation z.
+ * @param view The float action button's view.
+ * @param res The resources file.
+ */
+ public static void setupFloatingActionButton(View view, Resources res) {
+ if (CompatUtils.isLollipopCompatible()) {
+ view.setOutlineProvider(OVAL_OUTLINE_PROVIDER);
+ view.setTranslationZ(
+ res.getDimensionPixelSize(R.dimen.floating_action_button_translation_z));
+ }
+ }
+
+ /**
+ * Adds padding to the bottom of the given {@link ListView} so that the floating action button
+ * does not obscure any content.
+ *
+ * @param listView to add the padding to
+ * @param res valid resources object
+ */
+ public static void addBottomPaddingToListViewForFab(ListView listView, Resources res) {
+ final int fabPadding = res.getDimensionPixelSize(
+ R.dimen.floating_action_button_list_bottom_padding);
+ listView.setPaddingRelative(listView.getPaddingStart(), listView.getPaddingTop(),
+ listView.getPaddingEnd(), listView.getPaddingBottom() + fabPadding);
+ listView.setClipToPadding(false);
+ }
+}
diff --git a/src/com/android/contacts/common/util/WeakAsyncTask.java b/src/com/android/contacts/common/util/WeakAsyncTask.java
new file mode 100644
index 0000000..f46e514
--- /dev/null
+++ b/src/com/android/contacts/common/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.common.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/src/com/android/contacts/common/vcard/CancelActivity.java b/src/com/android/contacts/common/vcard/CancelActivity.java
new file mode 100644
index 0000000..8e393e1
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/CancelActivity.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 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.common.vcard;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.contacts.common.R;
+
+/**
+ * The Activity for canceling vCard import/export.
+ */
+public class CancelActivity extends Activity implements ServiceConnection {
+ private final String LOG_TAG = "VCardCancel";
+
+ /* package */ final static String JOB_ID = "job_id";
+ /* package */ final static String DISPLAY_NAME = "display_name";
+
+ /**
+ * Type of the process to be canceled. Only used for choosing appropriate title/message.
+ * Must be {@link VCardService#TYPE_IMPORT} or {@link VCardService#TYPE_EXPORT}.
+ */
+ /* package */ final static String TYPE = "type";
+
+ private class RequestCancelListener implements DialogInterface.OnClickListener {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ bindService(new Intent(CancelActivity.this,
+ VCardService.class), CancelActivity.this, Context.BIND_AUTO_CREATE);
+ }
+ }
+
+ private class CancelListener
+ implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ }
+
+ private final CancelListener mCancelListener = new CancelListener();
+ private int mJobId;
+ private String mDisplayName;
+ private int mType;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final Uri uri = getIntent().getData();
+ mJobId = Integer.parseInt(uri.getQueryParameter(JOB_ID));
+ mDisplayName = uri.getQueryParameter(DISPLAY_NAME);
+ mType = Integer.parseInt(uri.getQueryParameter(TYPE));
+ showDialog(R.id.dialog_cancel_confirmation);
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id, Bundle bundle) {
+ if (id == R.id.dialog_cancel_confirmation) {
+ final String message;
+ if (mType == VCardService.TYPE_IMPORT) {
+ message = getString(R.string.cancel_import_confirmation_message, mDisplayName);
+ } else {
+ message = getString(R.string.cancel_export_confirmation_message, mDisplayName);
+ }
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setMessage(message)
+ .setPositiveButton(android.R.string.ok, new RequestCancelListener())
+ .setOnCancelListener(mCancelListener)
+ .setNegativeButton(android.R.string.cancel, mCancelListener);
+ return builder.create();
+ } else if (id == R.id.dialog_cancel_failed) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(R.string.cancel_vcard_import_or_export_failed)
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setMessage(getString(R.string.fail_reason_unknown))
+ .setOnCancelListener(mCancelListener)
+ .setPositiveButton(android.R.string.ok, mCancelListener);
+ return builder.create();
+ } else {
+ Log.w(LOG_TAG, "Unknown dialog id: " + id);
+ return super.onCreateDialog(id, bundle);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder binder) {
+ VCardService service = ((VCardService.MyBinder) binder).getService();
+
+ try {
+ final CancelRequest request = new CancelRequest(mJobId, mDisplayName);
+ service.handleCancelRequest(request, null);
+ } finally {
+ unbindService(this);
+ }
+
+ finish();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // do nothing
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/CancelRequest.java b/src/com/android/contacts/common/vcard/CancelRequest.java
new file mode 100644
index 0000000..a5eb4aa
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/CancelRequest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010 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.common.vcard;
+
+/**
+ * Class representing one request for canceling vCard import/export.
+ */
+public class CancelRequest {
+ public final int jobId;
+ /**
+ * Name used for showing users some useful info. Typically a file name.
+ * Must not be used to do some actual operations.
+ */
+ public final String displayName;
+ public CancelRequest(int jobId, String displayName) {
+ this.jobId = jobId;
+ this.displayName = displayName;
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/ExportProcessor.java b/src/com/android/contacts/common/vcard/ExportProcessor.java
new file mode 100644
index 0000000..2aef379
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/ExportProcessor.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2010 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.common.vcard;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContactsEntity;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.contacts.common.R;
+import com.android.vcard.VCardComposer;
+import com.android.vcard.VCardConfig;
+
+import java.io.BufferedWriter;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+/**
+ * Class for processing one export request from a user. Dropped after exporting requested Uri(s).
+ * {@link VCardService} will create another object when there is another export request.
+ */
+public class ExportProcessor extends ProcessorBase {
+ private static final String LOG_TAG = "VCardExport";
+ private static final boolean DEBUG = VCardService.DEBUG;
+
+ private final VCardService mService;
+ private final ContentResolver mResolver;
+ private final NotificationManager mNotificationManager;
+ private final ExportRequest mExportRequest;
+ private final int mJobId;
+ private final String mCallingActivity;
+
+ private volatile boolean mCanceled;
+ private volatile boolean mDone;
+
+ private final int SHOW_READY_TOAST = 1;
+ private final Handler handler = new Handler() {
+ public void handleMessage(Message msg) {
+ if (msg.arg1 == SHOW_READY_TOAST) {
+ // This message is long, so we set the duration to LENGTH_LONG.
+ Toast.makeText(mService,
+ R.string.exporting_vcard_finished_toast, Toast.LENGTH_LONG).show();
+ }
+
+ }
+ };
+
+ public ExportProcessor(VCardService service, ExportRequest exportRequest, int jobId,
+ String callingActivity) {
+ mService = service;
+ mResolver = service.getContentResolver();
+ mNotificationManager =
+ (NotificationManager)mService.getSystemService(Context.NOTIFICATION_SERVICE);
+ mExportRequest = exportRequest;
+ mJobId = jobId;
+ mCallingActivity = callingActivity;
+ }
+
+ @Override
+ public final int getType() {
+ return VCardService.TYPE_EXPORT;
+ }
+
+ @Override
+ public void run() {
+ // ExecutorService ignores RuntimeException, so we need to show it here.
+ try {
+ runInternal();
+
+ if (isCancelled()) {
+ doCancelNotification();
+ }
+ } catch (OutOfMemoryError e) {
+ Log.e(LOG_TAG, "OutOfMemoryError thrown during import", e);
+ throw e;
+ } catch (RuntimeException e) {
+ Log.e(LOG_TAG, "RuntimeException thrown during export", e);
+ throw e;
+ } finally {
+ synchronized (this) {
+ mDone = true;
+ }
+ }
+ }
+
+ private void runInternal() {
+ if (DEBUG) Log.d(LOG_TAG, String.format("vCard export (id: %d) has started.", mJobId));
+ final ExportRequest request = mExportRequest;
+ VCardComposer composer = null;
+ Writer writer = null;
+ boolean successful = false;
+ try {
+ if (isCancelled()) {
+ Log.i(LOG_TAG, "Export request is cancelled before handling the request");
+ return;
+ }
+ final Uri uri = request.destUri;
+ final OutputStream outputStream;
+ try {
+ outputStream = mResolver.openOutputStream(uri);
+ } catch (FileNotFoundException e) {
+ Log.w(LOG_TAG, "FileNotFoundException thrown", e);
+ // Need concise title.
+
+ final String errorReason =
+ mService.getString(R.string.fail_reason_could_not_open_file,
+ uri, e.getMessage());
+ doFinishNotification(errorReason, null);
+ return;
+ }
+
+ final String exportType = request.exportType;
+ final int vcardType;
+ if (TextUtils.isEmpty(exportType)) {
+ vcardType = VCardConfig.getVCardTypeFromString(
+ mService.getString(R.string.config_export_vcard_type));
+ } else {
+ vcardType = VCardConfig.getVCardTypeFromString(exportType);
+ }
+
+ composer = new VCardComposer(mService, vcardType, true);
+
+ // for test
+ // int vcardType = (VCardConfig.VCARD_TYPE_V21_GENERIC |
+ // VCardConfig.FLAG_USE_QP_TO_PRIMARY_PROPERTIES);
+ // composer = new VCardComposer(ExportVCardActivity.this, vcardType, true);
+
+ writer = new BufferedWriter(new OutputStreamWriter(outputStream));
+ final Uri contentUriForRawContactsEntity = RawContactsEntity.CONTENT_URI;
+ // TODO: should provide better selection.
+ if (!composer.init(Contacts.CONTENT_URI, new String[] {Contacts._ID},
+ null, null,
+ null, contentUriForRawContactsEntity)) {
+ final String errorReason = composer.getErrorReason();
+ Log.e(LOG_TAG, "initialization of vCard composer failed: " + errorReason);
+ final String translatedErrorReason =
+ translateComposerError(errorReason);
+ final String title =
+ mService.getString(R.string.fail_reason_could_not_initialize_exporter,
+ translatedErrorReason);
+ doFinishNotification(title, null);
+ return;
+ }
+
+ final int total = composer.getCount();
+ if (total == 0) {
+ final String title =
+ mService.getString(R.string.fail_reason_no_exportable_contact);
+ doFinishNotification(title, null);
+ return;
+ }
+
+ int current = 1; // 1-origin
+ while (!composer.isAfterLast()) {
+ if (isCancelled()) {
+ Log.i(LOG_TAG, "Export request is cancelled during composing vCard");
+ return;
+ }
+ try {
+ writer.write(composer.createOneEntry());
+ } catch (IOException e) {
+ final String errorReason = composer.getErrorReason();
+ Log.e(LOG_TAG, "Failed to read a contact: " + errorReason);
+ final String translatedErrorReason =
+ translateComposerError(errorReason);
+ final String title =
+ mService.getString(R.string.fail_reason_error_occurred_during_export,
+ translatedErrorReason);
+ doFinishNotification(title, null);
+ return;
+ }
+
+ // vCard export is quite fast (compared to import), and frequent notifications
+ // bother notification bar too much.
+ if (current % 100 == 1) {
+ doProgressNotification(uri, total, current);
+ }
+ current++;
+ }
+ Log.i(LOG_TAG, "Successfully finished exporting vCard " + request.destUri);
+
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Ask MediaScanner to scan the file: " + request.destUri.getPath());
+ }
+ mService.updateMediaScanner(request.destUri.getPath());
+
+ successful = true;
+ final String filename = ExportVCardActivity.getOpenableUriDisplayName(mService, uri);
+ // If it is a local file (i.e. not a file from Drive), we need to allow user to share
+ // the file by pressing the notification; otherwise, it would be a file in Drive, we
+ // don't need to enable this action in notification since the file is already uploaded.
+ if (isLocalFile(uri)) {
+ final Message msg = handler.obtainMessage();
+ msg.arg1 = SHOW_READY_TOAST;
+ handler.sendMessage(msg);
+ doFinishNotificationWithShareAction(
+ mService.getString(R.string.exporting_vcard_finished_title_fallback),
+ mService.getString(R.string.touch_to_share_contacts), uri);
+ } else {
+ final String title = filename == null
+ ? mService.getString(R.string.exporting_vcard_finished_title_fallback)
+ : mService.getString(R.string.exporting_vcard_finished_title, filename);
+ doFinishNotification(title, null);
+ }
+ } finally {
+ if (composer != null) {
+ composer.terminate();
+ }
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (IOException e) {
+ Log.w(LOG_TAG, "IOException is thrown during close(). Ignored. " + e);
+ }
+ }
+ mService.handleFinishExportNotification(mJobId, successful);
+ }
+ }
+
+ private boolean isLocalFile(Uri uri) {
+ final String authority = uri.getAuthority();
+ return mService.getString(R.string.contacts_file_provider_authority).equals(authority);
+ }
+
+ private String translateComposerError(String errorMessage) {
+ final Resources resources = mService.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;
+ }
+ }
+
+ private void doProgressNotification(Uri uri, int totalCount, int currentCount) {
+ final String displayName = uri.getLastPathSegment();
+ final String description =
+ mService.getString(R.string.exporting_contact_list_message, displayName);
+ final String tickerText =
+ mService.getString(R.string.exporting_contact_list_title);
+ final Notification notification =
+ NotificationImportExportListener.constructProgressNotification(mService,
+ VCardService.TYPE_EXPORT, description, tickerText, mJobId, displayName,
+ totalCount, currentCount);
+ mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
+ mJobId, notification);
+ }
+
+ private void doCancelNotification() {
+ if (DEBUG) Log.d(LOG_TAG, "send cancel notification");
+ final String description = mService.getString(R.string.exporting_vcard_canceled_title,
+ mExportRequest.destUri.getLastPathSegment());
+ final Notification notification =
+ NotificationImportExportListener.constructCancelNotification(mService, description);
+ mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
+ mJobId, notification);
+ }
+
+ private void doFinishNotification(final String title, final String description) {
+ if (DEBUG) Log.d(LOG_TAG, "send finish notification: " + title + ", " + description);
+ final Intent intent = new Intent();
+ intent.setClassName(mService, mCallingActivity);
+ final Notification notification =
+ NotificationImportExportListener.constructFinishNotification(mService, title,
+ description, intent);
+ mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
+ mJobId, notification);
+ }
+
+ /**
+ * Pass intent with ACTION_SEND to notification so that user can press the notification to
+ * share contacts.
+ */
+ private void doFinishNotificationWithShareAction(final String title, final String
+ description, Uri uri) {
+ if (DEBUG) Log.d(LOG_TAG, "send finish notification: " + title + ", " + description);
+ final Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType(Contacts.CONTENT_VCARD_TYPE);
+ intent.putExtra(Intent.EXTRA_STREAM, uri);
+ // Securely grant access using temporary access permissions
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ // Build notification
+ final Notification notification =
+ NotificationImportExportListener.constructFinishNotificationWithFlags(
+ mService, title, description, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
+ mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
+ mJobId, notification);
+ }
+
+ @Override
+ public synchronized boolean cancel(boolean mayInterruptIfRunning) {
+ if (DEBUG) Log.d(LOG_TAG, "received cancel request");
+ if (mDone || mCanceled) {
+ return false;
+ }
+ mCanceled = true;
+ return true;
+ }
+
+ @Override
+ public synchronized boolean isCancelled() {
+ return mCanceled;
+ }
+
+ @Override
+ public synchronized boolean isDone() {
+ return mDone;
+ }
+
+ public ExportRequest getRequest() {
+ return mExportRequest;
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/ExportRequest.java b/src/com/android/contacts/common/vcard/ExportRequest.java
new file mode 100644
index 0000000..e05a32c
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/ExportRequest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 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.common.vcard;
+
+import android.net.Uri;
+
+public class ExportRequest {
+ public final Uri destUri;
+ /**
+ * Can be null.
+ */
+ public final String exportType;
+
+ public ExportRequest(Uri destUri) {
+ this(destUri, null);
+ }
+
+ public ExportRequest(Uri destUri, String exportType) {
+ this.destUri = destUri;
+ this.exportType = exportType;
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/ExportVCardActivity.java b/src/com/android/contacts/common/vcard/ExportVCardActivity.java
new file mode 100644
index 0000000..18de505
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/ExportVCardActivity.java
@@ -0,0 +1,246 @@
+/*
+ * 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.common.vcard;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.provider.OpenableColumns;
+import android.text.BidiFormatter;
+import android.text.TextDirectionHeuristics;
+import android.util.Log;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.activity.RequestImportVCardPermissionsActivity;
+
+import java.util.List;
+
+/**
+ * Shows a dialog confirming the export and asks actual vCard export to {@link VCardService}
+ *
+ * This Activity first connects to VCardService and ask an available file name and shows it to
+ * a user. After the user's confirmation, it send export request with the file name, assuming the
+ * file name is not reserved yet.
+ */
+public class ExportVCardActivity extends Activity implements ServiceConnection,
+ DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+ private static final String LOG_TAG = "VCardExport";
+ protected static final boolean DEBUG = VCardService.DEBUG;
+ private static final int REQUEST_CREATE_DOCUMENT = 100;
+
+ /**
+ * True when this Activity is connected to {@link VCardService}.
+ *
+ * Should be touched inside synchronized block.
+ */
+ protected boolean mConnected;
+
+ /**
+ * True when users need to do something and this Activity should not disconnect from
+ * VCardService. False when all necessary procedures are done (including sending export request)
+ * or there's some error occured.
+ */
+ private volatile boolean mProcessOngoing = true;
+
+ protected VCardService mService;
+ private static final BidiFormatter mBidiFormatter = BidiFormatter.getInstance();
+
+ // String for storing error reason temporarily.
+ private String mErrorReason;
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ if (RequestImportVCardPermissionsActivity.startPermissionActivity(this)) {
+ return;
+ }
+
+ if (!hasExportIntentHandler()) {
+ Log.e(LOG_TAG, "Couldn't find export intent handler");
+ showErrorDialog();
+ return;
+ }
+
+ connectVCardService();
+ }
+
+ private void connectVCardService() {
+ final String callingActivity = getIntent().getExtras()
+ .getString(VCardCommonArguments.ARG_CALLING_ACTIVITY);
+ Intent intent = new Intent(this, VCardService.class);
+ intent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY, callingActivity);
+
+ if (startService(intent) == null) {
+ Log.e(LOG_TAG, "Failed to start vCard service");
+ showErrorDialog();
+ return;
+ }
+
+ if (!bindService(intent, this, Context.BIND_AUTO_CREATE)) {
+ Log.e(LOG_TAG, "Failed to connect to vCard service.");
+ showErrorDialog();
+ }
+ // Continued to onServiceConnected()
+ }
+
+ private boolean hasExportIntentHandler() {
+ final Intent intent = getCreateDocIntent();
+ final List<ResolveInfo> receivers = getPackageManager().queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ return receivers != null && receivers.size() > 0;
+ }
+
+ private Intent getCreateDocIntent() {
+ final Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType(VCardService.X_VCARD_MIME_TYPE);
+ intent.putExtra(Intent.EXTRA_TITLE, mBidiFormatter.unicodeWrap(
+ getString(R.string.exporting_vcard_filename), TextDirectionHeuristics.LTR));
+ return intent;
+ }
+
+ private void showErrorDialog() {
+ mErrorReason = getString(R.string.fail_reason_unknown);
+ showDialog(R.id.dialog_fail_to_export_with_reason);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_CREATE_DOCUMENT) {
+ if (resultCode == Activity.RESULT_OK && mService != null &&
+ data != null && data.getData() != null) {
+ final Uri targetFileName = data.getData();
+ if (DEBUG) Log.d(LOG_TAG, "exporting to " + targetFileName);
+ final ExportRequest request = new ExportRequest(targetFileName);
+ // The connection object will call finish().
+ mService.handleExportRequest(request, new NotificationImportExportListener(
+ ExportVCardActivity.this));
+ } else if (DEBUG) {
+ if (mService == null) {
+ Log.d(LOG_TAG, "No vCard service.");
+ } else {
+ Log.d(LOG_TAG, "create document cancelled or no data returned");
+ }
+ }
+ finish();
+ }
+ }
+
+ @Override
+ public synchronized void onServiceConnected(ComponentName name, IBinder binder) {
+ if (DEBUG) Log.d(LOG_TAG, "connected to service, requesting a destination file name");
+ mConnected = true;
+ mService = ((VCardService.MyBinder) binder).getService();
+
+ // Have the user choose where vcards will be exported to
+ startActivityForResult(getCreateDocIntent(), REQUEST_CREATE_DOCUMENT);
+ }
+
+ // Use synchronized since we don't want to call finish() just after this call.
+ @Override
+ public synchronized void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.d(LOG_TAG, "onServiceDisconnected()");
+ mService = null;
+ mConnected = false;
+ if (mProcessOngoing) {
+ // Unexpected disconnect event.
+ Log.w(LOG_TAG, "Disconnected from service during the process ongoing.");
+ showErrorDialog();
+ }
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id, Bundle bundle) {
+ if (id == R.id.dialog_fail_to_export_with_reason) {
+ mProcessOngoing = false;
+ return new AlertDialog.Builder(this)
+ .setTitle(R.string.exporting_contact_failed_title)
+ .setMessage(getString(R.string.exporting_contact_failed_message,
+ mErrorReason != null ? mErrorReason :
+ getString(R.string.fail_reason_unknown)))
+ .setPositiveButton(android.R.string.ok, this)
+ .setOnCancelListener(this)
+ .create();
+ }
+ return super.onCreateDialog(id, bundle);
+ }
+
+ @Override
+ protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
+ if (id == R.id.dialog_fail_to_export_with_reason) {
+ ((AlertDialog)dialog).setMessage(mErrorReason);
+ } else {
+ super.onPrepareDialog(id, dialog, args);
+ }
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (DEBUG) Log.d(LOG_TAG, "ExportVCardActivity#onClick() is called");
+ finish();
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ if (DEBUG) Log.d(LOG_TAG, "ExportVCardActivity#onCancel() is called");
+ mProcessOngoing = false;
+ finish();
+ }
+
+ @Override
+ public void unbindService(ServiceConnection conn) {
+ mProcessOngoing = false;
+ super.unbindService(conn);
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mConnected) {
+ unbindService(this);
+ mConnected = false;
+ }
+ super.onDestroy();
+ }
+
+ /**
+ * Returns the display name for the given openable Uri or null if it could not be resolved. */
+ static String getOpenableUriDisplayName(Context context, Uri uri) {
+ if (uri == null) return null;
+ final Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
+ try {
+ if (cursor != null && cursor.moveToFirst()) {
+ return cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/ImportProcessor.java b/src/com/android/contacts/common/vcard/ImportProcessor.java
new file mode 100644
index 0000000..219ec14
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/ImportProcessor.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2010 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.common.vcard;
+
+import android.accounts.Account;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.util.Log;
+
+import com.android.vcard.VCardEntry;
+import com.android.vcard.VCardEntryCommitter;
+import com.android.vcard.VCardEntryConstructor;
+import com.android.vcard.VCardEntryHandler;
+import com.android.vcard.VCardInterpreter;
+import com.android.vcard.VCardParser;
+import com.android.vcard.VCardParser_V21;
+import com.android.vcard.VCardParser_V30;
+import com.android.vcard.exception.VCardException;
+import com.android.vcard.exception.VCardNestedException;
+import com.android.vcard.exception.VCardNotSupportedException;
+import com.android.vcard.exception.VCardVersionException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class for processing one import request from a user. Dropped after importing requested Uri(s).
+ * {@link VCardService} will create another object when there is another import request.
+ */
+public class ImportProcessor extends ProcessorBase implements VCardEntryHandler {
+ private static final String LOG_TAG = "VCardImport";
+ private static final boolean DEBUG = VCardService.DEBUG;
+
+ private final VCardService mService;
+ private final ContentResolver mResolver;
+ private final ImportRequest mImportRequest;
+ private final int mJobId;
+ private final VCardImportExportListener mListener;
+
+ // TODO: remove and show appropriate message instead.
+ private final List<Uri> mFailedUris = new ArrayList<Uri>();
+
+ private VCardParser mVCardParser;
+
+ private volatile boolean mCanceled;
+ private volatile boolean mDone;
+
+ private int mCurrentCount = 0;
+ private int mTotalCount = 0;
+
+ public ImportProcessor(final VCardService service, final VCardImportExportListener listener,
+ final ImportRequest request, final int jobId) {
+ mService = service;
+ mResolver = mService.getContentResolver();
+ mListener = listener;
+
+ mImportRequest = request;
+ mJobId = jobId;
+ }
+
+ @Override
+ public void onStart() {
+ // do nothing
+ }
+
+ @Override
+ public void onEnd() {
+ // do nothing
+ }
+
+ @Override
+ public void onEntryCreated(VCardEntry entry) {
+ mCurrentCount++;
+ if (mListener != null) {
+ mListener.onImportParsed(mImportRequest, mJobId, entry, mCurrentCount, mTotalCount);
+ }
+ }
+
+ @Override
+ public final int getType() {
+ return VCardService.TYPE_IMPORT;
+ }
+
+ @Override
+ public void run() {
+ // ExecutorService ignores RuntimeException, so we need to show it here.
+ try {
+ runInternal();
+
+ if (isCancelled() && mListener != null) {
+ mListener.onImportCanceled(mImportRequest, mJobId);
+ }
+ } catch (OutOfMemoryError e) {
+ Log.e(LOG_TAG, "OutOfMemoryError thrown during import", e);
+ throw e;
+ } catch (RuntimeException e) {
+ Log.e(LOG_TAG, "RuntimeException thrown during import", e);
+ throw e;
+ } finally {
+ synchronized (this) {
+ mDone = true;
+ }
+ }
+ }
+
+ private void runInternal() {
+ Log.i(LOG_TAG, String.format("vCard import (id: %d) has started.", mJobId));
+ final ImportRequest request = mImportRequest;
+ if (isCancelled()) {
+ Log.i(LOG_TAG, "Canceled before actually handling parameter (" + request.uri + ")");
+ return;
+ }
+ final int[] possibleVCardVersions;
+ if (request.vcardVersion == ImportVCardActivity.VCARD_VERSION_AUTO_DETECT) {
+ /**
+ * Note: this code assumes that a given Uri is able to be opened more than once,
+ * which may not be true in certain conditions.
+ */
+ possibleVCardVersions = new int[] {
+ ImportVCardActivity.VCARD_VERSION_V21,
+ ImportVCardActivity.VCARD_VERSION_V30
+ };
+ } else {
+ possibleVCardVersions = new int[] {
+ request.vcardVersion
+ };
+ }
+
+ final Uri uri = request.uri;
+ final Account account = request.account;
+ final int estimatedVCardType = request.estimatedVCardType;
+ final String estimatedCharset = request.estimatedCharset;
+ final int entryCount = request.entryCount;
+ mTotalCount += entryCount;
+
+ final VCardEntryConstructor constructor =
+ new VCardEntryConstructor(estimatedVCardType, account, estimatedCharset);
+ final VCardEntryCommitter committer = new VCardEntryCommitter(mResolver);
+ constructor.addEntryHandler(committer);
+ constructor.addEntryHandler(this);
+
+ InputStream is = null;
+ boolean successful = false;
+ try {
+ if (uri != null) {
+ Log.i(LOG_TAG, "start importing one vCard (Uri: " + uri + ")");
+ is = mResolver.openInputStream(uri);
+ } else if (request.data != null){
+ Log.i(LOG_TAG, "start importing one vCard (byte[])");
+ is = new ByteArrayInputStream(request.data);
+ }
+
+ if (is != null) {
+ successful = readOneVCard(is, estimatedVCardType, estimatedCharset, constructor,
+ possibleVCardVersions);
+ }
+ } catch (IOException e) {
+ successful = false;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ mService.handleFinishImportNotification(mJobId, successful);
+
+ if (successful) {
+ // TODO: successful becomes true even when cancelled. Should return more appropriate
+ // value
+ if (isCancelled()) {
+ Log.i(LOG_TAG, "vCard import has been canceled (uri: " + uri + ")");
+ // Cancel notification will be done outside this method.
+ } else {
+ Log.i(LOG_TAG, "Successfully finished importing one vCard file: " + uri);
+ List<Uri> uris = committer.getCreatedUris();
+ if (mListener != null) {
+ if (uris != null && uris.size() == 1) {
+ mListener.onImportFinished(mImportRequest, mJobId, uris.get(0));
+ } else {
+ if (uris == null || uris.size() == 0) {
+ // Not critical, but suspicious.
+ Log.w(LOG_TAG, "Created Uris is null or 0 length " +
+ "though the creation itself is successful.");
+ }
+ mListener.onImportFinished(mImportRequest, mJobId, null);
+ }
+ }
+ }
+ } else {
+ Log.w(LOG_TAG, "Failed to read one vCard file: " + uri);
+ mFailedUris.add(uri);
+ }
+ }
+
+ private boolean readOneVCard(InputStream is, int vcardType, String charset,
+ final VCardInterpreter interpreter,
+ final int[] possibleVCardVersions) {
+ boolean successful = false;
+ final int length = possibleVCardVersions.length;
+ for (int i = 0; i < length; i++) {
+ final int vcardVersion = possibleVCardVersions[i];
+ try {
+ if (i > 0 && (interpreter instanceof VCardEntryConstructor)) {
+ // Let the object clean up internal temporary objects,
+ ((VCardEntryConstructor) interpreter).clear();
+ }
+
+ // We need synchronized block here,
+ // since we need to handle mCanceled and mVCardParser at once.
+ // In the worst case, a user may call cancel() just before creating
+ // mVCardParser.
+ synchronized (this) {
+ mVCardParser = (vcardVersion == ImportVCardActivity.VCARD_VERSION_V30 ?
+ new VCardParser_V30(vcardType) :
+ new VCardParser_V21(vcardType));
+ if (isCancelled()) {
+ Log.i(LOG_TAG, "ImportProcessor already recieves cancel request, so " +
+ "send cancel request to vCard parser too.");
+ mVCardParser.cancel();
+ }
+ }
+ mVCardParser.parse(is, interpreter);
+
+ successful = true;
+ break;
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "IOException was emitted: " + e.getMessage());
+ } catch (VCardNestedException e) {
+ // This exception should not be thrown here. We should instead handle it
+ // in the preprocessing session in ImportVCardActivity, as we don't try
+ // to detect the type of given vCard here.
+ //
+ // TODO: Handle this case appropriately, which should mean we have to have
+ // code trying to auto-detect the type of given vCard twice (both in
+ // ImportVCardActivity and ImportVCardService).
+ Log.e(LOG_TAG, "Nested Exception is found.");
+ } catch (VCardNotSupportedException e) {
+ Log.e(LOG_TAG, e.toString());
+ } catch (VCardVersionException e) {
+ if (i == length - 1) {
+ Log.e(LOG_TAG, "Appropriate version for this vCard is not found.");
+ } else {
+ // We'll try the other (v30) version.
+ }
+ } catch (VCardException e) {
+ Log.e(LOG_TAG, e.toString());
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ return successful;
+ }
+
+ @Override
+ public synchronized boolean cancel(boolean mayInterruptIfRunning) {
+ if (DEBUG) Log.d(LOG_TAG, "ImportProcessor received cancel request");
+ if (mDone || mCanceled) {
+ return false;
+ }
+ mCanceled = true;
+ synchronized (this) {
+ if (mVCardParser != null) {
+ mVCardParser.cancel();
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public synchronized boolean isCancelled() {
+ return mCanceled;
+ }
+
+
+ @Override
+ public synchronized boolean isDone() {
+ return mDone;
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/ImportRequest.java b/src/com/android/contacts/common/vcard/ImportRequest.java
new file mode 100644
index 0000000..32efb99
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/ImportRequest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 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.common.vcard;
+
+import android.accounts.Account;
+import android.net.Uri;
+
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.vcard.VCardSourceDetector;
+
+/**
+ * Class representing one request for importing vCard (given as a Uri).
+ *
+ * Mainly used when {@link ImportVCardActivity} requests {@link VCardService}
+ * to import some specific Uri.
+ *
+ * Note: This object's accepting only One Uri does NOT mean that
+ * there's only one vCard entry inside the instance, as one Uri often has multiple
+ * vCard entries inside it.
+ */
+public class ImportRequest {
+ /**
+ * Can be null (typically when there's no Account available in the system).
+ */
+ public final Account account;
+
+ /**
+ * Uri to be imported. May have different content than originally given from users, so
+ * when displaying user-friendly information (e.g. "importing xxx.vcf"), use
+ * {@link #displayName} instead.
+ *
+ * If this is null {@link #data} contains the byte stream of the vcard.
+ */
+ public final Uri uri;
+
+ /**
+ * Holds the byte stream of the vcard, if {@link #uri} is null.
+ */
+ public final byte[] data;
+
+ /**
+ * String to be displayed to the user to indicate the source of the VCARD.
+ */
+ public final String displayName;
+
+ /**
+ * Can be {@link VCardSourceDetector#PARSE_TYPE_UNKNOWN}.
+ */
+ public final int estimatedVCardType;
+
+ /**
+ * Can be null, meaning no preferable charset is available.
+ */
+ public final String estimatedCharset;
+
+ /**
+ * Assumes that one Uri contains only one version, while there's a (tiny) possibility
+ * we may have two types in one vCard.
+ *
+ * e.g.
+ * BEGIN:VCARD
+ * VERSION:2.1
+ * ...
+ * END:VCARD
+ * BEGIN:VCARD
+ * VERSION:3.0
+ * ...
+ * END:VCARD
+ *
+ * We've never seen this kind of a file, but we may have to cope with it in the future.
+ */
+ public final int vcardVersion;
+
+ /**
+ * The count of vCard entries in {@link #uri}. A receiver of this object can use it
+ * when showing the progress of import. Thus a receiver must be able to torelate this
+ * variable being invalid because of vCard's limitation.
+ *
+ * vCard does not let us know this count without looking over a whole file content,
+ * which means we have to open and scan over {@link #uri} to know this value, while
+ * it may not be opened more than once (Uri does not require it to be opened multiple times
+ * and may become invalid after its close() request).
+ */
+ public final int entryCount;
+
+ public ImportRequest(AccountWithDataSet account,
+ byte[] data, Uri uri, String displayName, int estimatedType, String estimatedCharset,
+ int vcardVersion, int entryCount) {
+ this.account = account != null ? account.getAccountOrNull() : null;
+ this.data = data;
+ this.uri = uri;
+ this.displayName = displayName;
+ this.estimatedVCardType = estimatedType;
+ this.estimatedCharset = estimatedCharset;
+ this.vcardVersion = vcardVersion;
+ this.entryCount = entryCount;
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/ImportVCardActivity.java b/src/com/android/contacts/common/vcard/ImportVCardActivity.java
new file mode 100644
index 0000000..9da8c0b
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/ImportVCardActivity.java
@@ -0,0 +1,769 @@
+/*
+ * 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.common.vcard;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.ProgressDialog;
+import android.content.ClipData;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.provider.OpenableColumns;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.activity.RequestImportVCardPermissionsActivity;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.vcard.VCardEntryCounter;
+import com.android.vcard.VCardParser;
+import com.android.vcard.VCardParser_V21;
+import com.android.vcard.VCardParser_V30;
+import com.android.vcard.VCardSourceDetector;
+import com.android.vcard.exception.VCardException;
+import com.android.vcard.exception.VCardNestedException;
+import com.android.vcard.exception.VCardVersionException;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * The class letting users to import vCard. This includes the UI part for letting them select
+ * an Account and posssibly a file if there's no Uri is given from its caller Activity.
+ *
+ * Note that this Activity assumes that the instance is a "one-shot Activity", which will be
+ * finished (with the method {@link Activity#finish()}) after the import and never reuse
+ * any Dialog in the instance. So this code is careless about the management around managed
+ * dialogs stuffs (like how onCreateDialog() is used).
+ */
+public class ImportVCardActivity extends Activity {
+ private static final String LOG_TAG = "VCardImport";
+
+ private static final int SELECT_ACCOUNT = 0;
+
+ /* package */ final static int VCARD_VERSION_AUTO_DETECT = 0;
+ /* package */ final static int VCARD_VERSION_V21 = 1;
+ /* package */ final static int VCARD_VERSION_V30 = 2;
+
+ private static final int REQUEST_OPEN_DOCUMENT = 100;
+
+ /**
+ * Notification id used when error happened before sending an import request to VCardServer.
+ */
+ private static final int FAILURE_NOTIFICATION_ID = 1;
+
+ private static final String LOCAL_TMP_FILE_NAME_EXTRA =
+ "com.android.contacts.common.vcard.LOCAL_TMP_FILE_NAME";
+
+ private static final String SOURCE_URI_DISPLAY_NAME =
+ "com.android.contacts.common.vcard.SOURCE_URI_DISPLAY_NAME";
+
+ private static final String STORAGE_VCARD_URI_PREFIX = "file:///storage";
+
+ private AccountWithDataSet mAccount;
+
+ private ProgressDialog mProgressDialogForCachingVCard;
+
+ private VCardCacheThread mVCardCacheThread;
+ private ImportRequestConnection mConnection;
+ /* package */ VCardImportExportListener mListener;
+
+ private String mErrorMessage;
+
+ private Handler mHandler = new Handler();
+
+ // Runs on the UI thread.
+ 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;
+ }
+ @Override
+ public void run() {
+ if (!isFinishing()) {
+ showDialog(mResId);
+ }
+ }
+ }
+
+ private class CancelListener
+ implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ }
+
+ private CancelListener mCancelListener = new CancelListener();
+
+ private class ImportRequestConnection implements ServiceConnection {
+ private VCardService mService;
+
+ public void sendImportRequest(final List<ImportRequest> requests) {
+ Log.i(LOG_TAG, "Send an import request");
+ mService.handleImportRequest(requests, mListener);
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder binder) {
+ mService = ((VCardService.MyBinder) binder).getService();
+ Log.i(LOG_TAG,
+ String.format("Connected to VCardService. Kick a vCard cache thread (uri: %s)",
+ Arrays.toString(mVCardCacheThread.getSourceUris())));
+ mVCardCacheThread.start();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.i(LOG_TAG, "Disconnected from VCardService");
+ }
+ }
+
+ /**
+ * Caches given vCard files into a local directory, and sends actual import request to
+ * {@link VCardService}.
+ *
+ * We need to cache given files into local storage. One of reasons is that some data (as Uri)
+ * may have special permissions. Callers may allow only this Activity to access that content,
+ * not what this Activity launched (like {@link VCardService}).
+ */
+ private class VCardCacheThread extends Thread
+ implements DialogInterface.OnCancelListener {
+ private boolean mCanceled;
+ private PowerManager.WakeLock mWakeLock;
+ private VCardParser mVCardParser;
+ private final Uri[] mSourceUris; // Given from a caller.
+ private final String[] mSourceDisplayNames; // Display names for each Uri in mSourceUris.
+ private final byte[] mSource;
+ private final String mDisplayName;
+
+ public VCardCacheThread(final Uri[] sourceUris, String[] sourceDisplayNames) {
+ mSourceUris = sourceUris;
+ mSourceDisplayNames = sourceDisplayNames;
+ mSource = null;
+ final Context context = ImportVCardActivity.this;
+ final PowerManager powerManager =
+ (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(
+ PowerManager.SCREEN_DIM_WAKE_LOCK |
+ PowerManager.ON_AFTER_RELEASE, LOG_TAG);
+ mDisplayName = null;
+ }
+
+ @Override
+ public void finalize() {
+ if (mWakeLock != null && mWakeLock.isHeld()) {
+ Log.w(LOG_TAG, "WakeLock is being held.");
+ mWakeLock.release();
+ }
+ }
+
+ @Override
+ public void run() {
+ Log.i(LOG_TAG, "vCard cache thread starts running.");
+ if (mConnection == null) {
+ throw new NullPointerException("vCard cache thread must be launched "
+ + "after a service connection is established");
+ }
+
+ mWakeLock.acquire();
+ try {
+ if (mCanceled == true) {
+ Log.i(LOG_TAG, "vCard cache operation is canceled.");
+ return;
+ }
+
+ final Context context = ImportVCardActivity.this;
+ // Uris given from caller applications may not be opened twice: consider when
+ // it is not from local storage (e.g. "file:///...") but from some special
+ // provider (e.g. "content://...").
+ // Thus we have to once copy the content of Uri into local storage, and read
+ // it after it.
+ //
+ // We may be able to read content of each vCard file during copying them
+ // to local storage, but currently vCard code does not allow us to do so.
+ int cache_index = 0;
+ ArrayList<ImportRequest> requests = new ArrayList<ImportRequest>();
+ if (mSource != null) {
+ try {
+ requests.add(constructImportRequest(mSource, null, mDisplayName));
+ } catch (VCardException e) {
+ Log.e(LOG_TAG, "Maybe the file is in wrong format", e);
+ showFailureNotification(R.string.fail_reason_not_supported);
+ return;
+ }
+ } else {
+ int i = 0;
+ for (Uri sourceUri : mSourceUris) {
+ if (mCanceled) {
+ Log.i(LOG_TAG, "vCard cache operation is canceled.");
+ break;
+ }
+
+ String sourceDisplayName = mSourceDisplayNames[i++];
+
+ final ImportRequest request;
+ try {
+ request = constructImportRequest(null, sourceUri, sourceDisplayName);
+ } catch (VCardException e) {
+ Log.e(LOG_TAG, "Maybe the file is in wrong format", e);
+ showFailureNotification(R.string.fail_reason_not_supported);
+ return;
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Unexpected IOException", e);
+ showFailureNotification(R.string.fail_reason_io_error);
+ return;
+ }
+ if (mCanceled) {
+ Log.i(LOG_TAG, "vCard cache operation is canceled.");
+ return;
+ }
+ requests.add(request);
+ }
+ }
+ if (!requests.isEmpty()) {
+ mConnection.sendImportRequest(requests);
+ } else {
+ Log.w(LOG_TAG, "Empty import requests. Ignore it.");
+ }
+ } catch (OutOfMemoryError e) {
+ Log.e(LOG_TAG, "OutOfMemoryError occured during caching vCard");
+ System.gc();
+ runOnUiThread(new DialogDisplayer(
+ getString(R.string.fail_reason_low_memory_during_import)));
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "IOException during caching vCard", e);
+ runOnUiThread(new DialogDisplayer(
+ getString(R.string.fail_reason_io_error)));
+ } finally {
+ Log.i(LOG_TAG, "Finished caching vCard.");
+ mWakeLock.release();
+ unbindService(mConnection);
+ mProgressDialogForCachingVCard.dismiss();
+ mProgressDialogForCachingVCard = null;
+ finish();
+ }
+ }
+
+ /**
+ * Reads localDataUri (possibly multiple times) and constructs {@link ImportRequest} from
+ * its content.
+ *
+ * @arg localDataUri Uri actually used for the import. Should be stored in
+ * app local storage, as we cannot guarantee other types of Uris can be read
+ * multiple times. This variable populates {@link ImportRequest#uri}.
+ * @arg displayName Used for displaying information to the user. This variable populates
+ * {@link ImportRequest#displayName}.
+ */
+ private ImportRequest constructImportRequest(final byte[] data,
+ final Uri localDataUri, final String displayName)
+ throws IOException, VCardException {
+ final ContentResolver resolver = ImportVCardActivity.this.getContentResolver();
+ VCardEntryCounter counter = null;
+ VCardSourceDetector detector = null;
+ int vcardVersion = VCARD_VERSION_V21;
+ try {
+ boolean shouldUseV30 = false;
+ InputStream is;
+ if (data != null) {
+ is = new ByteArrayInputStream(data);
+ } else {
+ is = resolver.openInputStream(localDataUri);
+ }
+ mVCardParser = new VCardParser_V21();
+ try {
+ counter = new VCardEntryCounter();
+ detector = new VCardSourceDetector();
+ mVCardParser.addInterpreter(counter);
+ mVCardParser.addInterpreter(detector);
+ mVCardParser.parse(is);
+ } catch (VCardVersionException e1) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+
+ shouldUseV30 = true;
+ if (data != null) {
+ is = new ByteArrayInputStream(data);
+ } else {
+ is = resolver.openInputStream(localDataUri);
+ }
+ mVCardParser = new VCardParser_V30();
+ try {
+ counter = new VCardEntryCounter();
+ detector = new VCardSourceDetector();
+ mVCardParser.addInterpreter(counter);
+ mVCardParser.addInterpreter(detector);
+ mVCardParser.parse(is);
+ } catch (VCardVersionException e2) {
+ throw new VCardException("vCard with unspported version.");
+ }
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ vcardVersion = shouldUseV30 ? VCARD_VERSION_V30 : VCARD_VERSION_V21;
+ } catch (VCardNestedException e) {
+ Log.w(LOG_TAG, "Nested Exception is found (it may be false-positive).");
+ // Go through without throwing the Exception, as we may be able to detect the
+ // version before it
+ }
+ return new ImportRequest(mAccount,
+ data, localDataUri, displayName,
+ detector.getEstimatedType(),
+ detector.getEstimatedCharset(),
+ vcardVersion, counter.getCount());
+ }
+
+ public Uri[] getSourceUris() {
+ return mSourceUris;
+ }
+
+ public void cancel() {
+ mCanceled = true;
+ if (mVCardParser != null) {
+ mVCardParser.cancel();
+ }
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ Log.i(LOG_TAG, "Cancel request has come. Abort caching vCard.");
+ cancel();
+ }
+ }
+
+ private void importVCard(final Uri uri, final String sourceDisplayName) {
+ importVCard(new Uri[] {uri}, new String[] {sourceDisplayName});
+ }
+
+ private void importVCard(final Uri[] uris, final String[] sourceDisplayNames) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (!isFinishing()) {
+ mVCardCacheThread = new VCardCacheThread(uris, sourceDisplayNames);
+ mListener = new NotificationImportExportListener(ImportVCardActivity.this);
+ showDialog(R.id.dialog_cache_vcard);
+ }
+ }
+ });
+ }
+
+ private String getDisplayName(Uri sourceUri) {
+ if (sourceUri == null) {
+ return null;
+ }
+ final ContentResolver resolver = ImportVCardActivity.this.getContentResolver();
+ String displayName = null;
+ Cursor cursor = null;
+ // Try to get a display name from the given Uri. If it fails, we just
+ // pick up the last part of the Uri.
+ try {
+ cursor = resolver.query(sourceUri,
+ new String[] { OpenableColumns.DISPLAY_NAME },
+ null, null, null);
+ if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
+ if (cursor.getCount() > 1) {
+ Log.w(LOG_TAG, "Unexpected multiple rows: "
+ + cursor.getCount());
+ }
+ int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
+ if (index >= 0) {
+ displayName = cursor.getString(index);
+ }
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ if (TextUtils.isEmpty(displayName)){
+ displayName = sourceUri.getLastPathSegment();
+ }
+ return displayName;
+ }
+
+ /**
+ * Copy the content of sourceUri to the destination.
+ */
+ private Uri copyTo(final Uri sourceUri, String filename) throws IOException {
+ Log.i(LOG_TAG, String.format("Copy a Uri to app local storage (%s -> %s)",
+ sourceUri, filename));
+ final Context context = ImportVCardActivity.this;
+ final ContentResolver resolver = context.getContentResolver();
+ ReadableByteChannel inputChannel = null;
+ WritableByteChannel outputChannel = null;
+ Uri destUri = null;
+ try {
+ inputChannel = Channels.newChannel(resolver.openInputStream(sourceUri));
+ destUri = Uri.parse(context.getFileStreamPath(filename).toURI().toString());
+ outputChannel = context.openFileOutput(filename, Context.MODE_PRIVATE).getChannel();
+ final ByteBuffer buffer = ByteBuffer.allocateDirect(8192);
+ while (inputChannel.read(buffer) != -1) {
+ buffer.flip();
+ outputChannel.write(buffer);
+ buffer.compact();
+ }
+ buffer.flip();
+ while (buffer.hasRemaining()) {
+ outputChannel.write(buffer);
+ }
+ } finally {
+ if (inputChannel != null) {
+ try {
+ inputChannel.close();
+ } catch (IOException e) {
+ Log.w(LOG_TAG, "Failed to close inputChannel.");
+ }
+ }
+ if (outputChannel != null) {
+ try {
+ outputChannel.close();
+ } catch(IOException e) {
+ Log.w(LOG_TAG, "Failed to close outputChannel");
+ }
+ }
+ }
+ return destUri;
+ }
+
+ /**
+ * Reads the file from {@param sourceUri} and copies it to local cache file.
+ * Returns the local file name which stores the file from sourceUri.
+ */
+ private String readUriToLocalFile(Uri sourceUri) {
+ // Read the uri to local first.
+ int cache_index = 0;
+ String localFilename = null;
+ // Note: caches are removed by VCardService.
+ while (true) {
+ localFilename = VCardService.CACHE_FILE_PREFIX + cache_index + ".vcf";
+ final File file = getFileStreamPath(localFilename);
+ if (!file.exists()) {
+ break;
+ } else {
+ if (cache_index == Integer.MAX_VALUE) {
+ throw new RuntimeException("Exceeded cache limit");
+ }
+ cache_index++;
+ }
+ }
+ try {
+ copyTo(sourceUri, localFilename);
+ } catch (SecurityException e) {
+ Log.e(LOG_TAG, "SecurityException", e);
+ showFailureNotification(R.string.fail_reason_io_error);
+ return null;
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "IOException during caching vCard", e);
+ showFailureNotification(R.string.fail_reason_io_error);
+ return null;
+ }
+
+ if (localFilename == null) {
+ Log.e(LOG_TAG, "Cannot load uri to local storage.");
+ showFailureNotification(R.string.fail_reason_io_error);
+ return null;
+ }
+
+ return localFilename;
+ }
+
+ private Uri readUriToLocalUri(Uri sourceUri) {
+ final String fileName = readUriToLocalFile(sourceUri);
+ if (fileName == null) {
+ return null;
+ }
+ return Uri.parse(getFileStreamPath(fileName).toURI().toString());
+ }
+
+ // Returns true if uri is from Storage.
+ private boolean isStorageUri(Uri uri) {
+ return uri != null && uri.toString().startsWith(STORAGE_VCARD_URI_PREFIX);
+ }
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ Uri sourceUri = getIntent().getData();
+
+ // Reading uris from non-storage needs the permission granted from the source intent,
+ // instead of permissions from RequestImportVCardPermissionActivity. So skipping requesting
+ // permissions from RequestImportVCardPermissionActivity for uris from non-storage source.
+ if (isStorageUri(sourceUri)
+ && RequestImportVCardPermissionsActivity.startPermissionActivity(this)) {
+ return;
+ }
+
+ String sourceDisplayName = null;
+ if (sourceUri != null) {
+ // Read the uri to local first.
+ String localTmpFileName = getIntent().getStringExtra(LOCAL_TMP_FILE_NAME_EXTRA);
+ sourceDisplayName = getIntent().getStringExtra(SOURCE_URI_DISPLAY_NAME);
+ if (TextUtils.isEmpty(localTmpFileName)) {
+ localTmpFileName = readUriToLocalFile(sourceUri);
+ sourceDisplayName = getDisplayName(sourceUri);
+ if (localTmpFileName == null) {
+ Log.e(LOG_TAG, "Cannot load uri to local storage.");
+ showFailureNotification(R.string.fail_reason_io_error);
+ return;
+ }
+ getIntent().putExtra(LOCAL_TMP_FILE_NAME_EXTRA, localTmpFileName);
+ getIntent().putExtra(SOURCE_URI_DISPLAY_NAME, sourceDisplayName);
+ }
+ sourceUri = Uri.parse(getFileStreamPath(localTmpFileName).toURI().toString());
+ }
+
+ // Always request required permission for contacts before importing the vcard.
+ if (RequestImportVCardPermissionsActivity.startPermissionActivity(this)) {
+ return;
+ }
+
+ String accountName = null;
+ String accountType = null;
+ String dataSet = null;
+ final Intent intent = getIntent();
+ if (intent != null) {
+ accountName = intent.getStringExtra(SelectAccountActivity.ACCOUNT_NAME);
+ accountType = intent.getStringExtra(SelectAccountActivity.ACCOUNT_TYPE);
+ dataSet = intent.getStringExtra(SelectAccountActivity.DATA_SET);
+ } else {
+ Log.e(LOG_TAG, "intent does not exist");
+ }
+
+ if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
+ mAccount = new AccountWithDataSet(accountName, accountType, dataSet);
+ } else {
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
+ final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
+ if (accountList.size() == 0) {
+ mAccount = null;
+ } else if (accountList.size() == 1) {
+ mAccount = accountList.get(0);
+ } else {
+ startActivityForResult(new Intent(this, SelectAccountActivity.class),
+ SELECT_ACCOUNT);
+ return;
+ }
+ }
+
+ startImport(sourceUri, sourceDisplayName);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ if (requestCode == SELECT_ACCOUNT) {
+ if (resultCode == Activity.RESULT_OK) {
+ mAccount = new AccountWithDataSet(
+ intent.getStringExtra(SelectAccountActivity.ACCOUNT_NAME),
+ intent.getStringExtra(SelectAccountActivity.ACCOUNT_TYPE),
+ intent.getStringExtra(SelectAccountActivity.DATA_SET));
+ final Uri sourceUri = getIntent().getData();
+ if (sourceUri == null) {
+ startImport(sourceUri, /* sourceDisplayName =*/ null);
+ } else {
+ final String sourceDisplayName = getIntent().getStringExtra(
+ SOURCE_URI_DISPLAY_NAME);
+ final String localFileName = getIntent().getStringExtra(
+ LOCAL_TMP_FILE_NAME_EXTRA);
+ final Uri localUri = Uri.parse(
+ getFileStreamPath(localFileName).toURI().toString());
+ startImport(localUri, sourceDisplayName);
+ }
+ } else {
+ if (resultCode != Activity.RESULT_CANCELED) {
+ Log.w(LOG_TAG, "Result code was not OK nor CANCELED: " + resultCode);
+ }
+ finish();
+ }
+ } else if (requestCode == REQUEST_OPEN_DOCUMENT) {
+ if (resultCode == Activity.RESULT_OK) {
+ final ClipData clipData = intent.getClipData();
+ if (clipData != null) {
+ final ArrayList<Uri> uris = new ArrayList<>();
+ final ArrayList<String> sourceDisplayNames = new ArrayList<>();
+ for (int i = 0; i < clipData.getItemCount(); i++) {
+ ClipData.Item item = clipData.getItemAt(i);
+ final Uri uri = item.getUri();
+ if (uri != null) {
+ final Uri localUri = readUriToLocalUri(uri);
+ if (localUri != null) {
+ final String sourceDisplayName = getDisplayName(uri);
+ uris.add(localUri);
+ sourceDisplayNames.add(sourceDisplayName);
+ }
+ }
+ }
+ if (uris.isEmpty()) {
+ Log.w(LOG_TAG, "No vCard was selected for import");
+ finish();
+ } else {
+ Log.i(LOG_TAG, "Multiple vCards selected for import: " + uris);
+ importVCard(uris.toArray(new Uri[0]),
+ sourceDisplayNames.toArray(new String[0]));
+ }
+ } else {
+ final Uri uri = intent.getData();
+ if (uri != null) {
+ Log.i(LOG_TAG, "vCard selected for import: " + uri);
+ final Uri localUri = readUriToLocalUri(uri);
+ if (localUri != null) {
+ final String sourceDisplayName = getDisplayName(uri);
+ importVCard(localUri, sourceDisplayName);
+ } else {
+ Log.w(LOG_TAG, "No local URI for vCard import");
+ finish();
+ }
+ } else {
+ Log.w(LOG_TAG, "No vCard was selected for import");
+ finish();
+ }
+ }
+ } else {
+ if (resultCode != Activity.RESULT_CANCELED) {
+ Log.w(LOG_TAG, "Result code was not OK nor CANCELED" + resultCode);
+ }
+ finish();
+ }
+ }
+ }
+
+ private void startImport(Uri uri, String sourceDisplayName) {
+ // Handle inbound files
+ if (uri != null) {
+ Log.i(LOG_TAG, "Starting vCard import using Uri " + uri);
+ importVCard(uri, sourceDisplayName);
+ } else {
+ Log.i(LOG_TAG, "Start vCard without Uri. The user will select vCard manually.");
+ final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType(VCardService.X_VCARD_MIME_TYPE);
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ startActivityForResult(intent, REQUEST_OPEN_DOCUMENT);
+ }
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int resId, Bundle bundle) {
+ if (resId == R.id.dialog_cache_vcard) {
+ if (mProgressDialogForCachingVCard == null) {
+ final String title = getString(R.string.caching_vcard_title);
+ final String message = getString(R.string.caching_vcard_message);
+ mProgressDialogForCachingVCard = new ProgressDialog(this);
+ mProgressDialogForCachingVCard.setTitle(title);
+ mProgressDialogForCachingVCard.setMessage(message);
+ mProgressDialogForCachingVCard.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+ mProgressDialogForCachingVCard.setOnCancelListener(mVCardCacheThread);
+ startVCardService();
+ }
+ return mProgressDialogForCachingVCard;
+ } else if (resId == 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);
+ }
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(getString(R.string.reading_vcard_failed_title))
+ .setIconAttribute(android.R.attr.alertDialogIcon)
+ .setMessage(message)
+ .setOnCancelListener(mCancelListener)
+ .setPositiveButton(android.R.string.ok, mCancelListener);
+ return builder.create();
+ }
+
+ return super.onCreateDialog(resId, bundle);
+ }
+
+ /* package */ void startVCardService() {
+ mConnection = new ImportRequestConnection();
+
+ Log.i(LOG_TAG, "Bind to VCardService.");
+ // We don't want the service finishes itself just after this connection.
+ Intent intent = new Intent(this, VCardService.class);
+ startService(intent);
+ bindService(new Intent(this, VCardService.class),
+ mConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ if (mProgressDialogForCachingVCard != null) {
+ Log.i(LOG_TAG, "Cache thread is still running. Show progress dialog again.");
+ showDialog(R.id.dialog_cache_vcard);
+ }
+ }
+
+ /* package */ void showFailureNotification(int reasonId) {
+ final NotificationManager notificationManager =
+ (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
+ final Notification notification =
+ NotificationImportExportListener.constructImportFailureNotification(
+ ImportVCardActivity.this,
+ getString(reasonId));
+ notificationManager.notify(NotificationImportExportListener.FAILURE_NOTIFICATION_TAG,
+ FAILURE_NOTIFICATION_ID, notification);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(ImportVCardActivity.this,
+ getString(R.string.vcard_import_failed), Toast.LENGTH_LONG).show();
+ }
+ });
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/NfcImportVCardActivity.java b/src/com/android/contacts/common/vcard/NfcImportVCardActivity.java
new file mode 100644
index 0000000..0634df4
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/NfcImportVCardActivity.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2011 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.common.vcard;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.Uri;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.provider.ContactsContract.RawContacts;
+import android.util.Log;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.activity.RequestPermissionsActivity;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.util.ImplicitIntentsUtil;
+import com.android.vcard.VCardEntry;
+import com.android.vcard.VCardEntryCounter;
+import com.android.vcard.VCardParser;
+import com.android.vcard.VCardParser_V21;
+import com.android.vcard.VCardParser_V30;
+import com.android.vcard.VCardSourceDetector;
+import com.android.vcard.exception.VCardException;
+import com.android.vcard.exception.VCardNestedException;
+import com.android.vcard.exception.VCardVersionException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class NfcImportVCardActivity extends Activity implements ServiceConnection,
+ VCardImportExportListener {
+ private static final String TAG = "NfcImportVCardActivity";
+
+ private static final int SELECT_ACCOUNT = 1;
+
+ private NdefRecord mRecord;
+ private AccountWithDataSet mAccount;
+
+ /* package */ class ImportTask extends AsyncTask<VCardService, Void, ImportRequest> {
+ @Override
+ public ImportRequest doInBackground(VCardService... services) {
+ ImportRequest request = createImportRequest();
+ if (request == null) {
+ return null;
+ }
+
+ ArrayList<ImportRequest> requests = new ArrayList<ImportRequest>();
+ requests.add(request);
+ services[0].handleImportRequest(requests, NfcImportVCardActivity.this);
+ return request;
+ }
+
+ @Override
+ public void onCancelled() {
+ unbindService(NfcImportVCardActivity.this);
+ }
+
+ @Override
+ public void onPostExecute(ImportRequest request) {
+ unbindService(NfcImportVCardActivity.this);
+ }
+ }
+
+ /* package */ ImportRequest createImportRequest() {
+ VCardParser parser;
+ VCardEntryCounter counter = null;
+ VCardSourceDetector detector = null;
+ int vcardVersion = ImportVCardActivity.VCARD_VERSION_V21;
+ try {
+ ByteArrayInputStream is = new ByteArrayInputStream(mRecord.getPayload());
+ is.mark(0);
+ parser = new VCardParser_V21();
+ try {
+ counter = new VCardEntryCounter();
+ detector = new VCardSourceDetector();
+ parser.addInterpreter(counter);
+ parser.addInterpreter(detector);
+ parser.parse(is);
+ } catch (VCardVersionException e1) {
+ is.reset();
+ vcardVersion = ImportVCardActivity.VCARD_VERSION_V30;
+ parser = new VCardParser_V30();
+ try {
+ counter = new VCardEntryCounter();
+ detector = new VCardSourceDetector();
+ parser.addInterpreter(counter);
+ parser.addInterpreter(detector);
+ parser.parse(is);
+ } catch (VCardVersionException e2) {
+ return null;
+ }
+ } finally {
+ try {
+ if (is != null) is.close();
+ } catch (IOException e) {
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Failed reading vcard data", e);
+ return null;
+ } catch (VCardNestedException e) {
+ Log.w(TAG, "Nested Exception is found (it may be false-positive).");
+ // Go through without throwing the Exception, as we may be able to detect the
+ // version before it
+ } catch (VCardException e) {
+ Log.e(TAG, "Error parsing vcard", e);
+ return null;
+ }
+
+ return new ImportRequest(mAccount, mRecord.getPayload(), null,
+ getString(R.string.nfc_vcard_file_name), detector.getEstimatedType(),
+ detector.getEstimatedCharset(), vcardVersion, counter.getCount());
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder binder) {
+ VCardService service = ((VCardService.MyBinder) binder).getService();
+ new ImportTask().execute(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // Do nothing
+ }
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ if (RequestPermissionsActivity.startPermissionActivity(this)) {
+ return;
+ }
+
+ Intent intent = getIntent();
+ if (!NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
+ Log.w(TAG, "Unknowon intent " + intent);
+ finish();
+ return;
+ }
+
+ String type = intent.getType();
+ if (type == null ||
+ (!"text/x-vcard".equals(type) && !"text/vcard".equals(type))) {
+ Log.w(TAG, "Not a vcard");
+ //setStatus(getString(R.string.fail_reason_not_supported));
+ finish();
+ return;
+ }
+ NdefMessage msg = (NdefMessage) intent.getParcelableArrayExtra(
+ NfcAdapter.EXTRA_NDEF_MESSAGES)[0];
+ mRecord = msg.getRecords()[0];
+
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
+ final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
+ if (accountList.size() == 0) {
+ mAccount = null;
+ } else if (accountList.size() == 1) {
+ mAccount = accountList.get(0);
+ } else {
+ startActivityForResult(new Intent(this, SelectAccountActivity.class), SELECT_ACCOUNT);
+ return;
+ }
+
+ startImport();
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ if (requestCode == SELECT_ACCOUNT) {
+ if (resultCode == RESULT_OK) {
+ mAccount = new AccountWithDataSet(
+ intent.getStringExtra(SelectAccountActivity.ACCOUNT_NAME),
+ intent.getStringExtra(SelectAccountActivity.ACCOUNT_TYPE),
+ intent.getStringExtra(SelectAccountActivity.DATA_SET));
+ startImport();
+ } else {
+ finish();
+ }
+ }
+ }
+
+ private void startImport() {
+ // We don't want the service finishes itself just after this connection.
+ Intent intent = new Intent(this, VCardService.class);
+ startService(intent);
+ bindService(intent, this, Context.BIND_AUTO_CREATE);
+ }
+
+ @Override
+ public void onImportProcessed(ImportRequest request, int jobId, int sequence) {
+ // do nothing
+ }
+
+ @Override
+ public void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount,
+ int totalCount) {
+ // do nothing
+ }
+
+ @Override
+ public void onImportFinished(ImportRequest request, int jobId, Uri uri) {
+ if (isFinishing()) {
+ Log.i(TAG, "Late import -- ignoring");
+ return;
+ }
+
+ if (uri != null) {
+ Uri contactUri = RawContacts.getContactLookupUri(getContentResolver(), uri);
+ Intent intent = new Intent(Intent.ACTION_VIEW, contactUri);
+ ImplicitIntentsUtil.startActivityInAppIfPossible(this, intent);
+ finish();
+ }
+ }
+
+ @Override
+ public void onImportFailed(ImportRequest request) {
+ if (isFinishing()) {
+ Log.i(TAG, "Late import failure -- ignoring");
+ return;
+ }
+ // TODO: report failure
+ }
+
+ @Override
+ public void onImportCanceled(ImportRequest request, int jobId) {
+ // do nothing
+ }
+
+ @Override
+ public void onExportProcessed(ExportRequest request, int jobId) {
+ // do nothing
+ }
+
+ @Override
+ public void onExportFailed(ExportRequest request) {
+ // do nothing
+ }
+
+ @Override
+ public void onCancelRequest(CancelRequest request, int type) {
+ // do nothing
+ }
+
+ @Override
+ public void onComplete() {
+ // do nothing
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/NotificationImportExportListener.java b/src/com/android/contacts/common/vcard/NotificationImportExportListener.java
new file mode 100644
index 0000000..2ac8c1c
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/NotificationImportExportListener.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2011 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.common.vcard;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.RawContacts;
+import android.support.v4.app.NotificationCompat;
+import android.widget.Toast;
+
+import com.android.contacts.common.R;
+import com.android.vcard.VCardEntry;
+
+import java.text.NumberFormat;
+
+public class NotificationImportExportListener implements VCardImportExportListener,
+ Handler.Callback {
+ /** The tag used by vCard-related notifications. */
+ /* package */ static final String DEFAULT_NOTIFICATION_TAG = "VCardServiceProgress";
+ /**
+ * The tag used by vCard-related failure notifications.
+ * <p>
+ * Use a different tag from {@link #DEFAULT_NOTIFICATION_TAG} so that failures do not get
+ * replaced by other notifications and vice-versa.
+ */
+ /* package */ static final String FAILURE_NOTIFICATION_TAG = "VCardServiceFailure";
+
+ private final NotificationManager mNotificationManager;
+ private final Activity mContext;
+ private final Handler mHandler;
+
+ public NotificationImportExportListener(Activity activity) {
+ mContext = activity;
+ mNotificationManager = (NotificationManager) activity.getSystemService(
+ Context.NOTIFICATION_SERVICE);
+ mHandler = new Handler(this);
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ String text = (String) msg.obj;
+ Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
+ return true;
+ }
+
+ @Override
+ public void onImportProcessed(ImportRequest request, int jobId, int sequence) {
+ // Show a notification about the status
+ final String displayName;
+ final String message;
+ if (request.displayName != null) {
+ displayName = request.displayName;
+ message = mContext.getString(R.string.vcard_import_will_start_message, displayName);
+ } else {
+ displayName = mContext.getString(R.string.vcard_unknown_filename);
+ message = mContext.getString(
+ R.string.vcard_import_will_start_message_with_default_name);
+ }
+
+ // We just want to show notification for the first vCard.
+ if (sequence == 0) {
+ // TODO: Ideally we should detect the current status of import/export and
+ // show "started" when we can import right now and show "will start" when
+ // we cannot.
+ mHandler.obtainMessage(0, message).sendToTarget();
+ }
+
+ final Notification notification = constructProgressNotification(mContext,
+ VCardService.TYPE_IMPORT, message, message, jobId, displayName, -1, 0);
+ mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification);
+ }
+
+ @Override
+ public void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount,
+ int totalCount) {
+ if (entry.isIgnorable()) {
+ return;
+ }
+
+ final String totalCountString = String.valueOf(totalCount);
+ final String tickerText =
+ mContext.getString(R.string.progress_notifier_message,
+ String.valueOf(currentCount),
+ totalCountString,
+ entry.getDisplayName());
+ final String description = mContext.getString(R.string.importing_vcard_description,
+ entry.getDisplayName());
+
+ final Notification notification = constructProgressNotification(
+ mContext.getApplicationContext(), VCardService.TYPE_IMPORT, description, tickerText,
+ jobId, request.displayName, totalCount, currentCount);
+ mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification);
+ }
+
+ @Override
+ public void onImportFinished(ImportRequest request, int jobId, Uri createdUri) {
+ final String description = mContext.getString(R.string.importing_vcard_finished_title,
+ request.displayName);
+ final Intent intent;
+ if (createdUri != null) {
+ final long rawContactId = ContentUris.parseId(createdUri);
+ final Uri contactUri = RawContacts.getContactLookupUri(
+ mContext.getContentResolver(), ContentUris.withAppendedId(
+ RawContacts.CONTENT_URI, rawContactId));
+ intent = new Intent(Intent.ACTION_VIEW, contactUri);
+ } else {
+ intent = new Intent(Intent.ACTION_VIEW);
+ intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
+ }
+ intent.setPackage(mContext.getPackageName());
+ final Notification notification =
+ NotificationImportExportListener.constructFinishNotification(mContext,
+ description, null, intent);
+ mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
+ jobId, notification);
+ }
+
+ @Override
+ public void onImportFailed(ImportRequest request) {
+ // TODO: a little unkind to show Toast in this case, which is shown just a moment.
+ // Ideally we should show some persistent something users can notice more easily.
+ mHandler.obtainMessage(0,
+ mContext.getString(R.string.vcard_import_request_rejected_message)).sendToTarget();
+ }
+
+ @Override
+ public void onImportCanceled(ImportRequest request, int jobId) {
+ final String description = mContext.getString(R.string.importing_vcard_canceled_title,
+ request.displayName);
+ final Notification notification =
+ NotificationImportExportListener.constructCancelNotification(mContext, description);
+ mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
+ jobId, notification);
+ }
+
+ @Override
+ public void onExportProcessed(ExportRequest request, int jobId) {
+ final String displayName = ExportVCardActivity.getOpenableUriDisplayName(mContext,
+ request.destUri);
+ final String message = mContext.getString(R.string.contacts_export_will_start_message);
+
+ mHandler.obtainMessage(0, message).sendToTarget();
+ final Notification notification =
+ NotificationImportExportListener.constructProgressNotification(mContext,
+ VCardService.TYPE_EXPORT, message, message, jobId, displayName, -1, 0);
+ mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification);
+ }
+
+ @Override
+ public void onExportFailed(ExportRequest request) {
+ mHandler.obtainMessage(0,
+ mContext.getString(R.string.vcard_export_request_rejected_message)).sendToTarget();
+ }
+
+ @Override
+ public void onCancelRequest(CancelRequest request, int type) {
+ final String description = type == VCardService.TYPE_IMPORT ?
+ mContext.getString(R.string.importing_vcard_canceled_title, request.displayName) :
+ mContext.getString(R.string.exporting_vcard_canceled_title, request.displayName);
+ final Notification notification = constructCancelNotification(mContext, description);
+ mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, request.jobId, notification);
+ }
+
+ /**
+ * Constructs a {@link Notification} showing the current status of import/export.
+ * Users can cancel the process with the Notification.
+ *
+ * @param context
+ * @param type import/export
+ * @param description Content of the Notification.
+ * @param tickerText
+ * @param jobId
+ * @param displayName Name to be shown to the Notification (e.g. "finished importing XXXX").
+ * Typycally a file name.
+ * @param totalCount The number of vCard entries to be imported. Used to show progress bar.
+ * -1 lets the system show the progress bar with "indeterminate" state.
+ * @param currentCount The index of current vCard. Used to show progress bar.
+ */
+ /* package */ static Notification constructProgressNotification(
+ Context context, int type, String description, String tickerText,
+ int jobId, String displayName, int totalCount, int currentCount) {
+ // Note: We cannot use extra values here (like setIntExtra()), as PendingIntent doesn't
+ // preserve them across multiple Notifications. PendingIntent preserves the first extras
+ // (when flag is not set), or update them when PendingIntent#getActivity() is called
+ // (See PendingIntent#FLAG_UPDATE_CURRENT). In either case, we cannot preserve extras as we
+ // expect (for each vCard import/export request).
+ //
+ // We use query parameter in Uri instead.
+ // Scheme and Authority is arbitorary, assuming CancelActivity never refers them.
+ final Intent intent = new Intent(context, CancelActivity.class);
+ final Uri uri = (new Uri.Builder())
+ .scheme("invalidscheme")
+ .authority("invalidauthority")
+ .appendQueryParameter(CancelActivity.JOB_ID, String.valueOf(jobId))
+ .appendQueryParameter(CancelActivity.DISPLAY_NAME, displayName)
+ .appendQueryParameter(CancelActivity.TYPE, String.valueOf(type)).build();
+ intent.setData(uri);
+
+ final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+ builder.setOngoing(true)
+ .setProgress(totalCount, currentCount, totalCount == - 1)
+ .setTicker(tickerText)
+ .setContentTitle(description)
+ .setColor(context.getResources().getColor(R.color.dialtacts_theme_color))
+ .setSmallIcon(type == VCardService.TYPE_IMPORT
+ ? android.R.drawable.stat_sys_download
+ : android.R.drawable.stat_sys_upload)
+ .setContentIntent(PendingIntent.getActivity(context, 0, intent, 0));
+ if (totalCount > 0) {
+ String percentage =
+ NumberFormat.getPercentInstance().format((double) currentCount / totalCount);
+ builder.setContentText(percentage);
+ }
+ return builder.getNotification();
+ }
+
+ /**
+ * Constructs a Notification telling users the process is canceled.
+ *
+ * @param context
+ * @param description Content of the Notification
+ */
+ /* package */ static Notification constructCancelNotification(
+ Context context, String description) {
+ return new NotificationCompat.Builder(context)
+ .setAutoCancel(true)
+ .setSmallIcon(android.R.drawable.stat_notify_error)
+ .setColor(context.getResources().getColor(R.color.dialtacts_theme_color))
+ .setContentTitle(description)
+ .setContentText(description)
+ // Launch an intent that won't resolve to anything. Restrict the intent to this
+ // app to make sure that no other app can steal this pending-intent b/19296918.
+ .setContentIntent(PendingIntent
+ .getActivity(context, 0, new Intent(context.getPackageName(), null), 0))
+ .getNotification();
+ }
+
+ /**
+ * Constructs a Notification telling users the process is finished.
+ *
+ * @param context
+ * @param description Content of the Notification
+ * @param intent Intent to be launched when the Notification is clicked. Can be null.
+ */
+ /* package */ static Notification constructFinishNotification(
+ Context context, String title, String description, Intent intent) {
+ return constructFinishNotificationWithFlags(context, title, description, intent, 0);
+ }
+
+ /**
+ * @param flags use FLAG_ACTIVITY_NEW_TASK to set it as new task, to get rid of cached files.
+ */
+ /* package */ static Notification constructFinishNotificationWithFlags(
+ Context context, String title, String description, Intent intent, int flags) {
+ return new NotificationCompat.Builder(context)
+ .setAutoCancel(true)
+ .setColor(context.getResources().getColor(R.color.dialtacts_theme_color))
+ .setSmallIcon(R.drawable.ic_check_mark)
+ .setContentTitle(title)
+ .setContentText(description)
+ // If no intent provided, include an intent that won't resolve to anything.
+ // Restrict the intent to this app to make sure that no other app can steal this
+ // pending-intent b/19296918.
+ .setContentIntent(PendingIntent.getActivity(context, 0,
+ (intent != null ? intent : new Intent(context.getPackageName(), null)),
+ flags))
+ .getNotification();
+ }
+
+ /**
+ * Constructs a Notification telling the vCard import has failed.
+ *
+ * @param context
+ * @param reason The reason why the import has failed. Shown in description field.
+ */
+ /* package */ static Notification constructImportFailureNotification(
+ Context context, String reason) {
+ return new NotificationCompat.Builder(context)
+ .setAutoCancel(true)
+ .setColor(context.getResources().getColor(R.color.dialtacts_theme_color))
+ .setSmallIcon(android.R.drawable.stat_notify_error)
+ .setContentTitle(context.getString(R.string.vcard_import_failed))
+ .setContentText(reason)
+ // Launch an intent that won't resolve to anything. Restrict the intent to this
+ // app to make sure that no other app can steal this pending-intent b/19296918.
+ .setContentIntent(PendingIntent
+ .getActivity(context, 0, new Intent(context.getPackageName(), null), 0))
+ .getNotification();
+ }
+
+ @Override
+ public void onComplete() {
+ mContext.finish();
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/ProcessorBase.java b/src/com/android/contacts/common/vcard/ProcessorBase.java
new file mode 100644
index 0000000..abc859d
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/ProcessorBase.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2010 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.common.vcard;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A base processor class. One instance processes vCard one import/export request (imports a given
+ * vCard or exports a vCard). Expected to be used with {@link ExecutorService}.
+ *
+ * This instance starts itself with {@link #run()} method, and can be cancelled with
+ * {@link #cancel(boolean)}. Users can check the processor's status using {@link #isCancelled()}
+ * and {@link #isDone()} asynchronously.
+ *
+ * {@link #get()} and {@link #get(long, TimeUnit)}, which are form {@link Future}, aren't
+ * supported and {@link UnsupportedOperationException} will be just thrown when they are called.
+ */
+public abstract class ProcessorBase implements RunnableFuture<Object> {
+
+ /**
+ * @return the type of the processor. Must be {@link VCardService#TYPE_IMPORT} or
+ * {@link VCardService#TYPE_EXPORT}.
+ */
+ public abstract int getType();
+
+ @Override
+ public abstract void run();
+
+ /**
+ * Cancels this operation.
+ *
+ * @param mayInterruptIfRunning ignored. When this method is called, the instance
+ * stops processing and finish itself even if the thread is running.
+ *
+ * @see Future#cancel(boolean)
+ */
+ @Override
+ public abstract boolean cancel(boolean mayInterruptIfRunning);
+ @Override
+ public abstract boolean isCancelled();
+ @Override
+ public abstract boolean isDone();
+
+ /**
+ * Just throws {@link UnsupportedOperationException}.
+ */
+ @Override
+ public final Object get() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Just throws {@link UnsupportedOperationException}.
+ */
+ @Override
+ public final Object get(long timeout, TimeUnit unit) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/SelectAccountActivity.java b/src/com/android/contacts/common/vcard/SelectAccountActivity.java
new file mode 100644
index 0000000..387f3fb
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/SelectAccountActivity.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2010 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.common.vcard;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.util.AccountSelectionUtil;
+
+import java.util.List;
+
+public class SelectAccountActivity extends Activity {
+ private static final String LOG_TAG = "SelectAccountActivity";
+
+ public static final String ACCOUNT_NAME = "account_name";
+ public static final String ACCOUNT_TYPE = "account_type";
+ public static final String DATA_SET = "data_set";
+
+ private class CancelListener
+ implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+ public void onClick(DialogInterface dialog, int which) {
+ finish();
+ }
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+ }
+
+ private AccountSelectionUtil.AccountSelectedListener mAccountSelectionListener;
+
+ @Override
+ protected void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ // 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 int resId = R.string.import_from_vcf_file;
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
+ final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
+ if (accountList.size() == 0) {
+ Log.w(LOG_TAG, "Account does not exist");
+ finish();
+ return;
+ } else if (accountList.size() == 1) {
+ final AccountWithDataSet account = accountList.get(0);
+ final Intent intent = new Intent();
+ intent.putExtra(ACCOUNT_NAME, account.name);
+ intent.putExtra(ACCOUNT_TYPE, account.type);
+ intent.putExtra(DATA_SET, account.dataSet);
+ setResult(RESULT_OK, intent);
+ finish();
+ return;
+ }
+
+ Log.i(LOG_TAG, "The number of available accounts: " + accountList.size());
+
+ // Multiple accounts. Let users to select one.
+ mAccountSelectionListener =
+ new AccountSelectionUtil.AccountSelectedListener(
+ this, accountList, resId) {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ final AccountWithDataSet account = mAccountList.get(which);
+ final Intent intent = new Intent();
+ intent.putExtra(ACCOUNT_NAME, account.name);
+ intent.putExtra(ACCOUNT_TYPE, account.type);
+ intent.putExtra(DATA_SET, account.dataSet);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+ };
+ showDialog(resId);
+ return;
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int resId, Bundle bundle) {
+ if (resId == R.string.import_from_vcf_file) {
+ if (mAccountSelectionListener == null) {
+ throw new NullPointerException(
+ "mAccountSelectionListener must not be null.");
+ }
+ return AccountSelectionUtil.getSelectAccountDialog(this, resId,
+ mAccountSelectionListener,
+ new CancelListener());
+ }
+ return super.onCreateDialog(resId, bundle);
+ }
+}
diff --git a/src/com/android/contacts/common/vcard/ShareVCardActivity.java b/src/com/android/contacts/common/vcard/ShareVCardActivity.java
new file mode 100644
index 0000000..93868aa
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/ShareVCardActivity.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 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.common.vcard;
+
+import android.content.ComponentName;
+import android.net.Uri;
+import android.os.IBinder;
+import android.support.v4.content.FileProvider;
+import android.util.Log;
+
+import com.android.contacts.common.R;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * This activity connects to VCardService, creates a .vcf file in cache directory and send export
+ * request with the file URI so as to write contacts data to the file in background.
+ */
+public class ShareVCardActivity extends ExportVCardActivity {
+ private static final String LOG_TAG = "VCardShare";
+ private final String EXPORT_FILE_PREFIX = "vcards_";
+ private final long A_DAY_IN_MILLIS = 1000 * 60 * 60 * 24;
+
+ @Override
+ public synchronized void onServiceConnected(ComponentName name, IBinder binder) {
+ if (DEBUG) Log.d(LOG_TAG, "connected to service, requesting a destination file name");
+ mConnected = true;
+ mService = ((VCardService.MyBinder) binder).getService();
+
+ clearExportFiles();
+
+ final File file = getLocalFile();
+ try {
+ file.createNewFile();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Failed to create .vcf file, because: " + e);
+ finish();
+ return;
+ }
+
+ final Uri contentUri = FileProvider.getUriForFile(this,
+ getString(R.string.contacts_file_provider_authority), file);
+ if (DEBUG) Log.d(LOG_TAG, "exporting to " + contentUri);
+
+ final ExportRequest request = new ExportRequest(contentUri);
+ // The connection object will call finish().
+ mService.handleExportRequest(request, new NotificationImportExportListener(
+ ShareVCardActivity.this));
+ finish();
+ }
+
+ /**
+ * Delete the files (that are untouched for more than 1 day) in the cache directory.
+ * We cannot rely on VCardService to delete export files because it will delete export files
+ * right after finishing writing so no files could be shared. Therefore, our approach to
+ * deleting export files is:
+ * 1. put export files in cache directory so that Android may delete them;
+ * 2. manually delete the files that are older than 1 day when service is connected.
+ */
+ private void clearExportFiles() {
+ for (File file : getCacheDir().listFiles()) {
+ final long ageInMillis = System.currentTimeMillis() - file.lastModified();
+ if (file.getName().startsWith(EXPORT_FILE_PREFIX) && ageInMillis > A_DAY_IN_MILLIS) {
+ file.delete();
+ }
+ }
+ }
+
+ private File getLocalFile() {
+ final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
+ final String currentDateString = dateFormat.format(new Date()).toString();
+ final String localFilename = EXPORT_FILE_PREFIX + currentDateString + ".vcf";
+ return new File(getCacheDir(), localFilename);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/common/vcard/VCardCommonArguments.java b/src/com/android/contacts/common/vcard/VCardCommonArguments.java
new file mode 100644
index 0000000..c423ca3
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/VCardCommonArguments.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 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.common.vcard;
+
+/**
+ * Argument constants used by many activities and services.
+ */
+public class VCardCommonArguments {
+
+ // Argument used to pass calling activities to the target activity or service.
+ // The value should be a string class name (e.g. com.android.contacts.vcard.VCardCommonArgs)
+ public static final String ARG_CALLING_ACTIVITY = "CALLING_ACTIVITY";
+}
diff --git a/src/com/android/contacts/common/vcard/VCardImportExportListener.java b/src/com/android/contacts/common/vcard/VCardImportExportListener.java
new file mode 100644
index 0000000..e4e4893
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/VCardImportExportListener.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 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.common.vcard;
+
+import android.net.Uri;
+
+import com.android.vcard.VCardEntry;
+
+interface VCardImportExportListener {
+ void onImportProcessed(ImportRequest request, int jobId, int sequence);
+ void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount,
+ int totalCount);
+ void onImportFinished(ImportRequest request, int jobId, Uri uri);
+ void onImportFailed(ImportRequest request);
+ void onImportCanceled(ImportRequest request, int jobId);
+
+ void onExportProcessed(ExportRequest request, int jobId);
+ void onExportFailed(ExportRequest request);
+
+ void onCancelRequest(CancelRequest request, int type);
+ void onComplete();
+}
diff --git a/src/com/android/contacts/common/vcard/VCardService.java b/src/com/android/contacts/common/vcard/VCardService.java
new file mode 100644
index 0000000..1d7837b
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/VCardService.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2010 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.common.vcard;
+
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.MediaScannerConnection;
+import android.media.MediaScannerConnection.MediaScannerConnectionClient;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.contacts.common.R;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * The class responsible for handling vCard import/export requests.
+ *
+ * This Service creates one ImportRequest/ExportRequest object (as Runnable) per request and push
+ * it to {@link ExecutorService} with single thread executor. The executor handles each request
+ * one by one, and notifies users when needed.
+ */
+// TODO: Using IntentService looks simpler than using Service + ServiceConnection though this
+// works fine enough. Investigate the feasibility.
+public class VCardService extends Service {
+ private final static String LOG_TAG = "VCardService";
+
+ /* package */ final static boolean DEBUG = false;
+
+ /**
+ * Specifies the type of operation. Used when constructing a notification, canceling
+ * some operation, etc.
+ */
+ /* package */ static final int TYPE_IMPORT = 1;
+ /* package */ static final int TYPE_EXPORT = 2;
+
+ /* package */ static final String CACHE_FILE_PREFIX = "import_tmp_";
+
+ /* package */ static final String X_VCARD_MIME_TYPE = "text/x-vcard";
+
+ private class CustomMediaScannerConnectionClient implements MediaScannerConnectionClient {
+ final MediaScannerConnection mConnection;
+ final String mPath;
+
+ public CustomMediaScannerConnectionClient(String path) {
+ mConnection = new MediaScannerConnection(VCardService.this, this);
+ mPath = path;
+ }
+
+ public void start() {
+ mConnection.connect();
+ }
+
+ @Override
+ public void onMediaScannerConnected() {
+ if (DEBUG) { Log.d(LOG_TAG, "Connected to MediaScanner. Start scanning."); }
+ mConnection.scanFile(mPath, null);
+ }
+
+ @Override
+ public void onScanCompleted(String path, Uri uri) {
+ if (DEBUG) { Log.d(LOG_TAG, "scan completed: " + path); }
+ mConnection.disconnect();
+ removeConnectionClient(this);
+ }
+ }
+
+ // Should be single thread, as we don't want to simultaneously handle import and export
+ // requests.
+ private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
+
+ private int mCurrentJobId;
+
+ // Stores all unfinished import/export jobs which will be executed by mExecutorService.
+ // Key is jobId.
+ private final SparseArray<ProcessorBase> mRunningJobMap = new SparseArray<ProcessorBase>();
+ // Stores ScannerConnectionClient objects until they finish scanning requested files.
+ // Uses List class for simplicity. It's not costly as we won't have multiple objects in
+ // almost all cases.
+ private final List<CustomMediaScannerConnectionClient> mRemainingScannerConnections =
+ new ArrayList<CustomMediaScannerConnectionClient>();
+
+ private MyBinder mBinder;
+
+ private String mCallingActivity;
+
+ // File names currently reserved by some export job.
+ private final Set<String> mReservedDestination = new HashSet<String>();
+ /* ** end of vCard exporter params ** */
+
+ public class MyBinder extends Binder {
+ public VCardService getService() {
+ return VCardService.this;
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mBinder = new MyBinder();
+ if (DEBUG) Log.d(LOG_TAG, "vCard Service is being created.");
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int id) {
+ if (intent != null && intent.getExtras() != null) {
+ mCallingActivity = intent.getExtras().getString(
+ VCardCommonArguments.ARG_CALLING_ACTIVITY);
+ } else {
+ mCallingActivity = null;
+ }
+ return START_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ @Override
+ public void onDestroy() {
+ if (DEBUG) Log.d(LOG_TAG, "VCardService is being destroyed.");
+ cancelAllRequestsAndShutdown();
+ clearCache();
+ super.onDestroy();
+ }
+
+ public synchronized void handleImportRequest(List<ImportRequest> requests,
+ VCardImportExportListener listener) {
+ if (DEBUG) {
+ final ArrayList<String> uris = new ArrayList<String>();
+ final ArrayList<String> displayNames = new ArrayList<String>();
+ for (ImportRequest request : requests) {
+ uris.add(request.uri.toString());
+ displayNames.add(request.displayName);
+ }
+ Log.d(LOG_TAG,
+ String.format("received multiple import request (uri: %s, displayName: %s)",
+ uris.toString(), displayNames.toString()));
+ }
+ final int size = requests.size();
+ for (int i = 0; i < size; i++) {
+ ImportRequest request = requests.get(i);
+
+ if (tryExecute(new ImportProcessor(this, listener, request, mCurrentJobId))) {
+ if (listener != null) {
+ listener.onImportProcessed(request, mCurrentJobId, i);
+ }
+ mCurrentJobId++;
+ } else {
+ if (listener != null) {
+ listener.onImportFailed(request);
+ }
+ // A rejection means executor doesn't run any more. Exit.
+ break;
+ }
+ }
+ }
+
+ public synchronized void handleExportRequest(ExportRequest request,
+ VCardImportExportListener listener) {
+ if (tryExecute(new ExportProcessor(this, request, mCurrentJobId, mCallingActivity))) {
+ final String path = request.destUri.getEncodedPath();
+ if (DEBUG) Log.d(LOG_TAG, "Reserve the path " + path);
+ if (!mReservedDestination.add(path)) {
+ Log.w(LOG_TAG,
+ String.format("The path %s is already reserved. Reject export request",
+ path));
+ if (listener != null) {
+ listener.onExportFailed(request);
+ }
+ return;
+ }
+
+ if (listener != null) {
+ listener.onExportProcessed(request, mCurrentJobId);
+ }
+ mCurrentJobId++;
+ } else {
+ if (listener != null) {
+ listener.onExportFailed(request);
+ }
+ }
+ }
+
+ /**
+ * Tries to call {@link ExecutorService#execute(Runnable)} toward a given processor.
+ * @return true when successful.
+ */
+ private synchronized boolean tryExecute(ProcessorBase processor) {
+ try {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Executor service status: shutdown: " + mExecutorService.isShutdown()
+ + ", terminated: " + mExecutorService.isTerminated());
+ }
+ mExecutorService.execute(processor);
+ mRunningJobMap.put(mCurrentJobId, processor);
+ return true;
+ } catch (RejectedExecutionException e) {
+ Log.w(LOG_TAG, "Failed to excetute a job.", e);
+ return false;
+ }
+ }
+
+ public synchronized void handleCancelRequest(CancelRequest request,
+ VCardImportExportListener listener) {
+ final int jobId = request.jobId;
+ if (DEBUG) Log.d(LOG_TAG, String.format("Received cancel request. (id: %d)", jobId));
+
+ final ProcessorBase processor = mRunningJobMap.get(jobId);
+ mRunningJobMap.remove(jobId);
+
+ if (processor != null) {
+ processor.cancel(true);
+ final int type = processor.getType();
+ if (listener != null) {
+ listener.onCancelRequest(request, type);
+ }
+ if (type == TYPE_EXPORT) {
+ final String path =
+ ((ExportProcessor)processor).getRequest().destUri.getEncodedPath();
+ Log.i(LOG_TAG,
+ String.format("Cancel reservation for the path %s if appropriate", path));
+ if (!mReservedDestination.remove(path)) {
+ Log.w(LOG_TAG, "Not reserved.");
+ }
+ }
+ } else {
+ Log.w(LOG_TAG, String.format("Tried to remove unknown job (id: %d)", jobId));
+ }
+ stopServiceIfAppropriate();
+ }
+
+ /**
+ * Checks job list and call {@link #stopSelf()} when there's no job and no scanner connection
+ * is remaining.
+ * A new job (import/export) cannot be submitted any more after this call.
+ */
+ private synchronized void stopServiceIfAppropriate() {
+ if (mRunningJobMap.size() > 0) {
+ final int size = mRunningJobMap.size();
+
+ // Check if there are processors which aren't finished yet. If we still have ones to
+ // process, we cannot stop the service yet. Also clean up already finished processors
+ // here.
+
+ // Job-ids to be removed. At first all elements in the array are invalid and will
+ // be filled with real job-ids from the array's top. When we find a not-yet-finished
+ // processor, then we start removing those finished jobs. In that case latter half of
+ // this array will be invalid.
+ final int[] toBeRemoved = new int[size];
+ for (int i = 0; i < size; i++) {
+ final int jobId = mRunningJobMap.keyAt(i);
+ final ProcessorBase processor = mRunningJobMap.valueAt(i);
+ if (!processor.isDone()) {
+ Log.i(LOG_TAG, String.format("Found unfinished job (id: %d)", jobId));
+
+ // Remove processors which are already "done", all of which should be before
+ // processors which aren't done yet.
+ for (int j = 0; j < i; j++) {
+ mRunningJobMap.remove(toBeRemoved[j]);
+ }
+ return;
+ }
+
+ // Remember the finished processor.
+ toBeRemoved[i] = jobId;
+ }
+
+ // We're sure we can remove all. Instead of removing one by one, just call clear().
+ mRunningJobMap.clear();
+ }
+
+ if (!mRemainingScannerConnections.isEmpty()) {
+ Log.i(LOG_TAG, "MediaScanner update is in progress.");
+ return;
+ }
+
+ Log.i(LOG_TAG, "No unfinished job. Stop this service.");
+ mExecutorService.shutdown();
+ stopSelf();
+ }
+
+ /* package */ synchronized void updateMediaScanner(String path) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "MediaScanner is being updated: " + path);
+ }
+
+ if (mExecutorService.isShutdown()) {
+ Log.w(LOG_TAG, "MediaScanner update is requested after executor's being shut down. " +
+ "Ignoring the update request");
+ return;
+ }
+ final CustomMediaScannerConnectionClient client =
+ new CustomMediaScannerConnectionClient(path);
+ mRemainingScannerConnections.add(client);
+ client.start();
+ }
+
+ private synchronized void removeConnectionClient(
+ CustomMediaScannerConnectionClient client) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Removing custom MediaScannerConnectionClient.");
+ }
+ mRemainingScannerConnections.remove(client);
+ stopServiceIfAppropriate();
+ }
+
+ /* package */ synchronized void handleFinishImportNotification(
+ int jobId, boolean successful) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, String.format("Received vCard import finish notification (id: %d). "
+ + "Result: %b", jobId, (successful ? "success" : "failure")));
+ }
+ mRunningJobMap.remove(jobId);
+ stopServiceIfAppropriate();
+ }
+
+ /* package */ synchronized void handleFinishExportNotification(
+ int jobId, boolean successful) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, String.format("Received vCard export finish notification (id: %d). "
+ + "Result: %b", jobId, (successful ? "success" : "failure")));
+ }
+ final ProcessorBase job = mRunningJobMap.get(jobId);
+ mRunningJobMap.remove(jobId);
+ if (job == null) {
+ Log.w(LOG_TAG, String.format("Tried to remove unknown job (id: %d)", jobId));
+ } else if (!(job instanceof ExportProcessor)) {
+ Log.w(LOG_TAG,
+ String.format("Removed job (id: %s) isn't ExportProcessor", jobId));
+ } else {
+ final String path = ((ExportProcessor)job).getRequest().destUri.getEncodedPath();
+ if (DEBUG) Log.d(LOG_TAG, "Remove reserved path " + path);
+ mReservedDestination.remove(path);
+ }
+
+ stopServiceIfAppropriate();
+ }
+
+ /**
+ * Cancels all the import/export requests and calls {@link ExecutorService#shutdown()}, which
+ * means this Service becomes no longer ready for import/export requests.
+ *
+ * Mainly called from onDestroy().
+ */
+ private synchronized void cancelAllRequestsAndShutdown() {
+ for (int i = 0; i < mRunningJobMap.size(); i++) {
+ mRunningJobMap.valueAt(i).cancel(true);
+ }
+ mRunningJobMap.clear();
+ mExecutorService.shutdown();
+ }
+
+ /**
+ * Removes import caches stored locally.
+ */
+ private void clearCache() {
+ for (final String fileName : fileList()) {
+ if (fileName.startsWith(CACHE_FILE_PREFIX)) {
+ // We don't want to keep all the caches so we remove cache files old enough.
+ Log.i(LOG_TAG, "Remove a temporary file: " + fileName);
+ deleteFile(fileName);
+ }
+ }
+ }
+}
diff --git a/src/com/android/contacts/common/widget/ActivityTouchLinearLayout.java b/src/com/android/contacts/common/widget/ActivityTouchLinearLayout.java
new file mode 100644
index 0000000..d81526e
--- /dev/null
+++ b/src/com/android/contacts/common/widget/ActivityTouchLinearLayout.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 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.common.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.LinearLayout;
+
+import com.android.contacts.common.interactions.TouchPointManager;
+
+/**
+ * Linear layout for an activity that listens to all touch events on the screen and saves the touch
+ * point.
+ * Typically touch events are handled by child views--this class intercepts those touch events
+ * before passing them on to the child.
+ */
+public class ActivityTouchLinearLayout extends LinearLayout {
+ public ActivityTouchLinearLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent (MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ TouchPointManager.getInstance().setPoint((int) ev.getRawX(), (int) ev.getRawY());
+ }
+ return false;
+ }
+}
diff --git a/src/com/android/contacts/common/widget/FloatingActionButtonController.java b/src/com/android/contacts/common/widget/FloatingActionButtonController.java
new file mode 100644
index 0000000..0e94df1
--- /dev/null
+++ b/src/com/android/contacts/common/widget/FloatingActionButtonController.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2014 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.common.widget;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.view.View;
+import android.widget.ImageButton;
+
+import com.android.contacts.common.util.ViewUtil;
+import com.android.contacts.common.R;
+import com.android.phone.common.animation.AnimUtils;
+
+/**
+ * Controls the movement and appearance of the FAB (Floating Action Button).
+ */
+public class FloatingActionButtonController {
+ public static final int ALIGN_MIDDLE = 0;
+ public static final int ALIGN_QUARTER_END = 1;
+ public static final int ALIGN_END = 2;
+
+ private static final int FAB_SCALE_IN_DURATION = 186;
+ private static final int FAB_SCALE_IN_FADE_IN_DELAY = 70;
+ private static final int FAB_ICON_FADE_OUT_DURATION = 46;
+
+ private final int mAnimationDuration;
+ private final int mFloatingActionButtonWidth;
+ private final int mFloatingActionButtonMarginRight;
+ private final View mFloatingActionButtonContainer;
+ private final ImageButton mFloatingActionButton;
+ private final Interpolator mFabInterpolator;
+ private int mScreenWidth;
+
+ public FloatingActionButtonController(Activity activity, View container, ImageButton button) {
+ Resources resources = activity.getResources();
+ mFabInterpolator = AnimationUtils.loadInterpolator(activity,
+ android.R.interpolator.fast_out_slow_in);
+ mFloatingActionButtonWidth = resources.getDimensionPixelSize(
+ R.dimen.floating_action_button_width);
+ mFloatingActionButtonMarginRight = resources.getDimensionPixelOffset(
+ R.dimen.floating_action_button_margin_right);
+ mAnimationDuration = resources.getInteger(
+ R.integer.floating_action_button_animation_duration);
+ mFloatingActionButtonContainer = container;
+ mFloatingActionButton = button;
+ ViewUtil.setupFloatingActionButton(mFloatingActionButtonContainer, resources);
+ }
+
+ /**
+ * Passes the screen width into the class. Necessary for translation calculations.
+ * Should be called as soon as parent View width is available.
+ *
+ * @param screenWidth The width of the screen in pixels.
+ */
+ public void setScreenWidth(int screenWidth) {
+ mScreenWidth = screenWidth;
+ }
+
+ /**
+ * Sets FAB as View.VISIBLE or View.GONE.
+ *
+ * @param visible Whether or not to make the container visible.
+ */
+ public void setVisible(boolean visible) {
+ mFloatingActionButtonContainer.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
+ public boolean isVisible() {
+ return mFloatingActionButtonContainer.getVisibility() == View.VISIBLE;
+ }
+
+ public void changeIcon(Drawable icon, String description) {
+ if (mFloatingActionButton.getDrawable() != icon
+ || !mFloatingActionButton.getContentDescription().equals(description)) {
+ mFloatingActionButton.setImageDrawable(icon);
+ mFloatingActionButton.setContentDescription(description);
+ }
+ }
+
+ /**
+ * Updates the FAB location (middle to right position) as the PageView scrolls.
+ *
+ * @param positionOffset A fraction used to calculate position of the FAB during page scroll.
+ */
+ public void onPageScrolled(float positionOffset) {
+ // As the page is scrolling, if we're on the first tab, update the FAB position so it
+ // moves along with it.
+ mFloatingActionButtonContainer.setTranslationX(
+ (int) (positionOffset * getTranslationXForAlignment(ALIGN_END)));
+ }
+
+ /**
+ * Aligns the FAB to the described location
+ *
+ * @param align One of ALIGN_MIDDLE, ALIGN_QUARTER_RIGHT, or ALIGN_RIGHT.
+ * @param animate Whether or not to animate the transition.
+ */
+ public void align(int align, boolean animate) {
+ align(align, 0 /*offsetX */, 0 /* offsetY */, animate);
+ }
+
+ /**
+ * Aligns the FAB to the described location plus specified additional offsets.
+ *
+ * @param align One of ALIGN_MIDDLE, ALIGN_QUARTER_RIGHT, or ALIGN_RIGHT.
+ * @param offsetX Additional offsetX to translate by.
+ * @param offsetY Additional offsetY to translate by.
+ * @param animate Whether or not to animate the transition.
+ */
+ public void align(int align, int offsetX, int offsetY, boolean animate) {
+ if (mScreenWidth == 0) {
+ return;
+ }
+
+ int translationX = getTranslationXForAlignment(align);
+
+ // Skip animation if container is not shown; animation causes container to show again.
+ if (animate && mFloatingActionButtonContainer.isShown()) {
+ mFloatingActionButtonContainer.animate()
+ .translationX(translationX + offsetX)
+ .translationY(offsetY)
+ .setInterpolator(mFabInterpolator)
+ .setDuration(mAnimationDuration)
+ .start();
+ } else {
+ mFloatingActionButtonContainer.setTranslationX(translationX + offsetX);
+ mFloatingActionButtonContainer.setTranslationY(offsetY);
+ }
+ }
+
+ /**
+ * Resizes width and height of the floating action bar container.
+ * @param dimension The new dimensions for the width and height.
+ * @param animate Whether to animate this change.
+ */
+ public void resize(int dimension, boolean animate) {
+ if (animate) {
+ AnimUtils.changeDimensions(mFloatingActionButtonContainer, dimension, dimension);
+ } else {
+ mFloatingActionButtonContainer.getLayoutParams().width = dimension;
+ mFloatingActionButtonContainer.getLayoutParams().height = dimension;
+ mFloatingActionButtonContainer.requestLayout();
+ }
+ }
+
+ /**
+ * Scales the floating action button from no height and width to its actual dimensions. This is
+ * an animation for showing the floating action button.
+ * @param delayMs The delay for the effect, in milliseconds.
+ */
+ public void scaleIn(int delayMs) {
+ setVisible(true);
+ AnimUtils.scaleIn(mFloatingActionButtonContainer, FAB_SCALE_IN_DURATION, delayMs);
+ AnimUtils.fadeIn(mFloatingActionButton, FAB_SCALE_IN_DURATION,
+ delayMs + FAB_SCALE_IN_FADE_IN_DELAY, null);
+ }
+
+ /**
+ * Immediately remove the affects of the last call to {@link #scaleOut}.
+ */
+ public void resetIn() {
+ mFloatingActionButton.setAlpha(1f);
+ mFloatingActionButton.setVisibility(View.VISIBLE);
+ mFloatingActionButtonContainer.setScaleX(1);
+ mFloatingActionButtonContainer.setScaleY(1);
+ }
+
+ /**
+ * Scales the floating action button from its actual dimensions to no height and width. This is
+ * an animation for hiding the floating action button.
+ */
+ public void scaleOut() {
+ AnimUtils.scaleOut(mFloatingActionButtonContainer, mAnimationDuration);
+ // Fade out the icon faster than the scale out animation, so that the icon scaling is less
+ // obvious. We don't want it to scale, but the resizing the container is not as performant.
+ AnimUtils.fadeOut(mFloatingActionButton, FAB_ICON_FADE_OUT_DURATION, null);
+ }
+
+ /**
+ * Calculates the X offset of the FAB to the given alignment, adjusted for whether or not the
+ * view is in RTL mode.
+ *
+ * @param align One of ALIGN_MIDDLE, ALIGN_QUARTER_RIGHT, or ALIGN_RIGHT.
+ * @return The translationX for the given alignment.
+ */
+ public int getTranslationXForAlignment(int align) {
+ int result = 0;
+ switch (align) {
+ case ALIGN_MIDDLE:
+ // Moves the FAB to exactly center screen.
+ return 0;
+ case ALIGN_QUARTER_END:
+ // Moves the FAB a quarter of the screen width.
+ result = mScreenWidth / 4;
+ break;
+ case ALIGN_END:
+ // Moves the FAB half the screen width. Same as aligning right with a marginRight.
+ result = mScreenWidth / 2
+ - mFloatingActionButtonWidth / 2
+ - mFloatingActionButtonMarginRight;
+ break;
+ }
+ if (isLayoutRtl()) {
+ result *= -1;
+ }
+ return result;
+ }
+
+ private boolean isLayoutRtl() {
+ return mFloatingActionButtonContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ }
+}
diff --git a/src/com/android/contacts/common/widget/LayoutSuppressingImageView.java b/src/com/android/contacts/common/widget/LayoutSuppressingImageView.java
new file mode 100644
index 0000000..abcf786
--- /dev/null
+++ b/src/com/android/contacts/common/widget/LayoutSuppressingImageView.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+/**
+ * Custom {@link ImageView} that improves layouting performance.
+ *
+ * This improves the performance by not passing requestLayout() to its parent, taking advantage
+ * of knowing that image size won't change once set.
+ */
+public class LayoutSuppressingImageView extends ImageView {
+
+ public LayoutSuppressingImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void requestLayout() {
+ forceLayout();
+ }
+}
diff --git a/src/com/android/contacts/common/widget/LayoutSuppressingQuickContactBadge.java b/src/com/android/contacts/common/widget/LayoutSuppressingQuickContactBadge.java
new file mode 100644
index 0000000..1f48f5d
--- /dev/null
+++ b/src/com/android/contacts/common/widget/LayoutSuppressingQuickContactBadge.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.QuickContactBadge;
+
+/**
+ * Custom {@link QuickContactBadge} that improves layouting performance.
+ *
+ * This improves the performance by not passing requestLayout() to its parent, taking advantage
+ * of knowing that image size won't change once set.
+ */
+public class LayoutSuppressingQuickContactBadge extends QuickContactBadge {
+
+ public LayoutSuppressingQuickContactBadge(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void requestLayout() {
+ forceLayout();
+ }
+}
diff --git a/src/com/android/contacts/common/widget/ProportionalLayout.java b/src/com/android/contacts/common/widget/ProportionalLayout.java
new file mode 100644
index 0000000..5a5ac29
--- /dev/null
+++ b/src/com/android/contacts/common/widget/ProportionalLayout.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2012 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.common.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.contacts.common.R;
+
+/**
+ * Layout that calculates its height based on its width, or vice versa (depending on the set
+ * {@link #setDirection(Direction)}. The factor is specified in {@link #setRatio(float)}.
+ * <p>For {@link Direction#heightToWidth}: width := height * factor</p>
+ * <p>For {@link Direction#widthToHeight}: height := width * factor</p>
+ * <p>Only one child is allowed; if more are required, another ViewGroup can be used as the direct
+ * child of this layout.</p>
+ */
+public class ProportionalLayout extends ViewGroup {
+ /** Specifies whether the width should be calculated based on the height or vice-versa */
+ public enum Direction {
+ widthToHeight("widthToHeight"),
+ heightToWidth("heightToWidth");
+
+ public final String XmlName;
+
+ private Direction(String xmlName) {
+ XmlName = xmlName;
+ }
+
+ /**
+ * Parses the given direction string and returns the Direction instance. This
+ * should be used when inflating from xml
+ */
+ public static Direction parse(String value) {
+ if (widthToHeight.XmlName.equals(value)) {
+ return Direction.widthToHeight;
+ } else if (heightToWidth.XmlName.equals(value)) {
+ return Direction.heightToWidth;
+ } else {
+ throw new IllegalStateException("direction must be either " +
+ widthToHeight.XmlName + " or " + heightToWidth.XmlName);
+ }
+ }
+ }
+
+ private Direction mDirection;
+ private float mRatio;
+
+ public ProportionalLayout(Context context) {
+ super(context);
+ }
+
+ public ProportionalLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initFromAttributes(context, attrs);
+ }
+
+ public ProportionalLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initFromAttributes(context, attrs);
+ }
+
+ private void initFromAttributes(Context context, AttributeSet attrs) {
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProportionalLayout);
+
+ mDirection = Direction.parse(a.getString(R.styleable.ProportionalLayout_direction));
+ mRatio = a.getFloat(R.styleable.ProportionalLayout_ratio, 1.0f);
+
+ a.recycle();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (getChildCount() != 1) {
+ throw new IllegalStateException("ProportionalLayout requires exactly one child");
+ }
+
+ final View child = getChildAt(0);
+
+ // Do a first pass to get the optimal size
+ measureChild(child, widthMeasureSpec, heightMeasureSpec);
+ final int childWidth = child.getMeasuredWidth();
+ final int childHeight = child.getMeasuredHeight();
+
+ final int width;
+ final int height;
+ if (mDirection == Direction.heightToWidth) {
+ width = Math.round(childHeight * mRatio);
+ height = childHeight;
+ } else {
+ width = childWidth;
+ height = Math.round(childWidth * mRatio);
+ }
+
+ // Do a second pass so that all children are informed of the new size
+ measureChild(child,
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+
+ setMeasuredDimension(
+ resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (getChildCount() != 1) {
+ throw new IllegalStateException("ProportionalLayout requires exactly one child");
+ }
+
+ final View child = getChildAt(0);
+ child.layout(0, 0, right-left, bottom-top);
+ }
+
+ public Direction getDirection() {
+ return mDirection;
+ }
+
+ public void setDirection(Direction direction) {
+ mDirection = direction;
+ }
+
+ public float getRatio() {
+ return mRatio;
+ }
+
+ public void setRatio(float ratio) {
+ mRatio = ratio;
+ }
+}
diff --git a/src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java b/src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
new file mode 100644
index 0000000..709ce41
--- /dev/null
+++ b/src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2014 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.common.widget;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.compat.PhoneAccountCompat;
+import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Dialog that allows the user to select a phone accounts for a given action. Optionally provides
+ * the choice to set the phone account as default.
+ */
+public class SelectPhoneAccountDialogFragment extends DialogFragment {
+ private static final String ARG_TITLE_RES_ID = "title_res_id";
+ private static final String ARG_CAN_SET_DEFAULT = "can_set_default";
+ private static final String ARG_ACCOUNT_HANDLES = "account_handles";
+ private static final String ARG_IS_DEFAULT_CHECKED = "is_default_checked";
+ private static final String ARG_LISTENER = "listener";
+
+ private int mTitleResId;
+ private boolean mCanSetDefault;
+ private List<PhoneAccountHandle> mAccountHandles;
+ private boolean mIsSelected;
+ private boolean mIsDefaultChecked;
+ private TelecomManager mTelecomManager;
+ private SelectPhoneAccountListener mListener;
+
+ /**
+ * Create new fragment instance with default title and no option to set as default.
+ *
+ * @param accountHandles The {@code PhoneAccountHandle}s available to select from.
+ * @param listener The listener for the results of the account selection.
+ */
+ public static SelectPhoneAccountDialogFragment newInstance(
+ List<PhoneAccountHandle> accountHandles, SelectPhoneAccountListener listener) {
+ return newInstance(R.string.select_account_dialog_title, false,
+ accountHandles, listener);
+ }
+
+ /**
+ * Create new fragment instance.
+ * This method also allows specifying a custom title and "set default" checkbox.
+ *
+ * @param titleResId The resource ID for the string to use in the title of the dialog.
+ * @param canSetDefault {@code true} if the dialog should include an option to set the selection
+ * as the default. False otherwise.
+ * @param accountHandles The {@code PhoneAccountHandle}s available to select from.
+ * @param listener The listener for the results of the account selection.
+ */
+ public static SelectPhoneAccountDialogFragment newInstance(int titleResId,
+ boolean canSetDefault, List<PhoneAccountHandle> accountHandles,
+ SelectPhoneAccountListener listener) {
+ ArrayList<PhoneAccountHandle> accountHandlesCopy = new ArrayList<PhoneAccountHandle>();
+ if (accountHandles != null) {
+ accountHandlesCopy.addAll(accountHandles);
+ }
+ SelectPhoneAccountDialogFragment fragment = new SelectPhoneAccountDialogFragment();
+ final Bundle args = new Bundle();
+ args.putInt(ARG_TITLE_RES_ID, titleResId);
+ args.putBoolean(ARG_CAN_SET_DEFAULT, canSetDefault);
+ args.putParcelableArrayList(ARG_ACCOUNT_HANDLES, accountHandlesCopy);
+ args.putParcelable(ARG_LISTENER, listener);
+ fragment.setArguments(args);
+ fragment.setListener(listener);
+ return fragment;
+ }
+
+ public SelectPhoneAccountDialogFragment() {
+ }
+
+ public void setListener(SelectPhoneAccountListener listener) {
+ mListener = listener;
+ }
+
+ public static class SelectPhoneAccountListener extends ResultReceiver {
+ static final int RESULT_SELECTED = 1;
+ static final int RESULT_DISMISSED = 2;
+
+ static final String EXTRA_SELECTED_ACCOUNT_HANDLE = "extra_selected_account_handle";
+ static final String EXTRA_SET_DEFAULT = "extra_set_default";
+
+ public SelectPhoneAccountListener() {
+ super(new Handler());
+ }
+
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == RESULT_SELECTED) {
+ onPhoneAccountSelected(
+ (PhoneAccountHandle) resultData.getParcelable(
+ EXTRA_SELECTED_ACCOUNT_HANDLE),
+ resultData.getBoolean(EXTRA_SET_DEFAULT));
+ } else if (resultCode == RESULT_DISMISSED) {
+ onDialogDismissed();
+ }
+ }
+
+ public void onPhoneAccountSelected(PhoneAccountHandle selectedAccountHandle,
+ boolean setDefault) {}
+
+ public void onDialogDismissed() {}
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(ARG_IS_DEFAULT_CHECKED, mIsDefaultChecked);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ mTitleResId = getArguments().getInt(ARG_TITLE_RES_ID);
+ mCanSetDefault = getArguments().getBoolean(ARG_CAN_SET_DEFAULT);
+ mAccountHandles = getArguments().getParcelableArrayList(ARG_ACCOUNT_HANDLES);
+ mListener = getArguments().getParcelable(ARG_LISTENER);
+ if (savedInstanceState != null) {
+ mIsDefaultChecked = savedInstanceState.getBoolean(ARG_IS_DEFAULT_CHECKED);
+ }
+ mIsSelected = false;
+ mTelecomManager =
+ (TelecomManager) getActivity().getSystemService(Context.TELECOM_SERVICE);
+
+ final DialogInterface.OnClickListener selectionListener =
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mIsSelected = true;
+ PhoneAccountHandle selectedAccountHandle = mAccountHandles.get(which);
+ final Bundle result = new Bundle();
+ result.putParcelable(SelectPhoneAccountListener.EXTRA_SELECTED_ACCOUNT_HANDLE,
+ selectedAccountHandle);
+ result.putBoolean(SelectPhoneAccountListener.EXTRA_SET_DEFAULT,
+ mIsDefaultChecked);
+ if (mListener != null) {
+ mListener.onReceiveResult(SelectPhoneAccountListener.RESULT_SELECTED, result);
+ }
+ }
+ };
+
+ final CompoundButton.OnCheckedChangeListener checkListener =
+ new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton check, boolean isChecked) {
+ mIsDefaultChecked = isChecked;
+ }
+ };
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ ListAdapter selectAccountListAdapter = new SelectAccountListAdapter(
+ builder.getContext(),
+ R.layout.select_account_list_item,
+ mAccountHandles);
+
+ AlertDialog dialog = builder.setTitle(mTitleResId)
+ .setAdapter(selectAccountListAdapter, selectionListener)
+ .create();
+
+ if (mCanSetDefault) {
+ // Generate custom checkbox view
+ LinearLayout checkboxLayout = (LinearLayout) getActivity()
+ .getLayoutInflater()
+ .inflate(R.layout.default_account_checkbox, null);
+
+ CheckBox cb =
+ (CheckBox) checkboxLayout.findViewById(R.id.default_account_checkbox_view);
+ cb.setOnCheckedChangeListener(checkListener);
+ cb.setChecked(mIsDefaultChecked);
+
+ dialog.getListView().addFooterView(checkboxLayout);
+ }
+
+ return dialog;
+ }
+
+ private class SelectAccountListAdapter extends ArrayAdapter<PhoneAccountHandle> {
+ private int mResId;
+
+ public SelectAccountListAdapter(
+ Context context, int resource, List<PhoneAccountHandle> accountHandles) {
+ super(context, resource, accountHandles);
+ mResId = resource;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ LayoutInflater inflater = (LayoutInflater)
+ getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ View rowView;
+ final ViewHolder holder;
+
+ if (convertView == null) {
+ // Cache views for faster scrolling
+ rowView = inflater.inflate(mResId, null);
+ holder = new ViewHolder();
+ holder.labelTextView = (TextView) rowView.findViewById(R.id.label);
+ holder.numberTextView = (TextView) rowView.findViewById(R.id.number);
+ holder.imageView = (ImageView) rowView.findViewById(R.id.icon);
+ rowView.setTag(holder);
+ }
+ else {
+ rowView = convertView;
+ holder = (ViewHolder) rowView.getTag();
+ }
+
+ PhoneAccountHandle accountHandle = getItem(position);
+ PhoneAccount account = mTelecomManager.getPhoneAccount(accountHandle);
+ if (account == null) {
+ return rowView;
+ }
+ holder.labelTextView.setText(account.getLabel());
+ if (account.getAddress() == null ||
+ TextUtils.isEmpty(account.getAddress().getSchemeSpecificPart())) {
+ holder.numberTextView.setVisibility(View.GONE);
+ } else {
+ holder.numberTextView.setVisibility(View.VISIBLE);
+ holder.numberTextView.setText(
+ PhoneNumberUtilsCompat.createTtsSpannable(
+ account.getAddress().getSchemeSpecificPart()));
+ }
+ holder.imageView.setImageDrawable(PhoneAccountCompat.createIconDrawable(account,
+ getContext()));
+ return rowView;
+ }
+
+ private class ViewHolder {
+ TextView labelTextView;
+ TextView numberTextView;
+ ImageView imageView;
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (!mIsSelected && mListener != null) {
+ mListener.onReceiveResult(SelectPhoneAccountListener.RESULT_DISMISSED, null);
+ }
+ super.onStop();
+ }
+}
diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
index c1e5af8..d149f16 100644
--- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
@@ -788,6 +788,15 @@
// Save menu is invisible when there's only one read only contact in the editor.
saveMenu.setVisible(!mRawContactDisplayAloneIsReadOnly);
+ if (saveMenu.isVisible()) {
+ // Since we're using a custom action layout we have to manually hook up the handler.
+ saveMenu.getActionView().setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onOptionsItemSelected(saveMenu);
+ }
+ });
+ }
if (mRawContactIdToDisplayAlone != -1 || mIsUserProfile) {
sendToVoiceMailMenu.setVisible(false);
diff --git a/src/com/android/contacts/editor/GroupMembershipView.java b/src/com/android/contacts/editor/GroupMembershipView.java
index d41991c..ba0c2c6 100644
--- a/src/com/android/contacts/editor/GroupMembershipView.java
+++ b/src/com/android/contacts/editor/GroupMembershipView.java
@@ -38,9 +38,9 @@
import com.android.contacts.GroupMetaDataLoader;
import com.android.contacts.R;
+import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.interactions.GroupCreationDialogFragment;
-import com.android.contacts.interactions.GroupCreationDialogFragment.OnGroupCreatedListener;
+import com.android.contacts.group.GroupNameEditDialogFragment;
import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.RawContactModifier;
@@ -56,6 +56,8 @@
public class GroupMembershipView extends LinearLayout
implements OnClickListener, OnItemClickListener {
+ public static final String TAG_CREATE_GROUP_FRAGMENT = "createGroupDialog";
+
private static final int CREATE_NEW_GROUP_GROUP_ID = 133;
public static final class GroupSelectionItem {
@@ -449,17 +451,23 @@
UiClosables.closeQuietly(mPopup);
mPopup = null;
- GroupCreationDialogFragment.show(
+ final GroupNameEditDialogFragment dialog =
+ GroupNameEditDialogFragment.newInstanceForCreation(
+ new AccountWithDataSet(mAccountName, mAccountType, mDataSet), null);
+
+ // If the device is rotated after the dialog is shown, the listener will become null,
+ // so that the popup from GroupMembershipView will not be shown.
+ dialog.setListener(new GroupNameEditDialogFragment.Listener() {
+ @Override
+ public void onGroupNameEditStarted(String groupName) {
+ mCreatedNewGroup = true;
+ }
+ @Override
+ public void onGroupNameEditCancelled() { }
+ });
+ dialog.show(
((Activity) getContext()).getFragmentManager(),
- mAccountType,
- mAccountName,
- mDataSet,
- new OnGroupCreatedListener() {
- @Override
- public void onGroupCreated() {
- mCreatedNewGroup = true;
- }
- });
+ TAG_CREATE_GROUP_FRAGMENT);
}
}
diff --git a/src/com/android/contacts/editor/LabeledEditorView.java b/src/com/android/contacts/editor/LabeledEditorView.java
index 61c1061..947f35e 100644
--- a/src/com/android/contacts/editor/LabeledEditorView.java
+++ b/src/com/android/contacts/editor/LabeledEditorView.java
@@ -37,6 +37,7 @@
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
+import android.widget.CheckedTextView;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -44,10 +45,10 @@
import android.widget.TextView;
import com.android.contacts.R;
-import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.ContactsUtils;
-import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType.EditType;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.util.DialogManager;
@@ -86,6 +87,7 @@
private DialogManager mDialogManager = null;
private EditorListener mListener;
protected int mMinLineItemHeight;
+ private int mSelectedLabelIndex;
/**
* A marker in the spinner adapter of the currently selected custom type.
@@ -292,6 +294,7 @@
*/
public void rebuildLabel() {
mEditTypeAdapter = new EditTypeAdapter(getContext());
+ mEditTypeAdapter.setSelectedIndex(mSelectedLabelIndex);
mLabel.setAdapter(mEditTypeAdapter);
if (mEditTypeAdapter.hasCustomSelection()) {
mLabel.setSelection(mEditTypeAdapter.getPosition(CUSTOM_SELECTION));
@@ -518,6 +521,7 @@
// User picked type, and we're sure it's ok to actually write the entry.
mType = selected;
mEntry.put(mKind.typeColumn, mType.rawValue);
+ mSelectedLabelIndex = position;
rebuildLabel();
requestFocusForFirstEditField();
onLabelRebuilt();
@@ -563,6 +567,7 @@
private boolean mHasCustomSelection;
private int mTextColorHintUnfocused;
private int mTextColorDark;
+ private int mSelectedIndex;
public EditTypeAdapter(Context context) {
super(context, 0);
@@ -609,8 +614,11 @@
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
- return createViewFromResource(
+ final CheckedTextView dropDownView = (CheckedTextView) createViewFromResource(
position, convertView, parent, android.R.layout.simple_spinner_dropdown_item);
+ dropDownView.setBackground(getContext().getDrawable(R.drawable.drawer_item_background));
+ dropDownView.setChecked(position == mSelectedIndex);
+ return dropDownView;
}
private TextView createViewFromResource(int position, View convertView, ViewGroup parent,
@@ -636,5 +644,9 @@
textView.setText(text);
return textView;
}
+
+ public void setSelectedIndex(int selectedIndex) {
+ mSelectedIndex = selectedIndex;
+ }
}
}
diff --git a/src/com/android/contacts/group/GroupNameEditDialogFragment.java b/src/com/android/contacts/group/GroupNameEditDialogFragment.java
index 235a878..b2bfd0b 100644
--- a/src/com/android/contacts/group/GroupNameEditDialogFragment.java
+++ b/src/com/android/contacts/group/GroupNameEditDialogFragment.java
@@ -17,11 +17,18 @@
import android.app.Dialog;
import android.app.DialogFragment;
-import android.app.FragmentManager;
+import android.app.LoaderManager;
import android.content.Context;
+import android.content.CursorLoader;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.Loader;
+import android.database.Cursor;
+import android.net.Uri;
import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.TextUtils;
@@ -33,60 +40,99 @@
import android.widget.EditText;
import android.widget.TextView;
+import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.google.common.base.Strings;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
/**
* Edits the name of a group.
*/
-public final class GroupNameEditDialogFragment extends DialogFragment {
+public final class GroupNameEditDialogFragment extends DialogFragment implements
+ LoaderManager.LoaderCallbacks<Cursor> {
- private static final String KEY_IS_INSERT = "isInsert";
private static final String KEY_GROUP_NAME = "groupName";
private static final String ARG_IS_INSERT = "isInsert";
private static final String ARG_GROUP_NAME = "groupName";
+ private static final String ARG_ACCOUNT = "account";
+ private static final String ARG_CALLBACK_ACTION = "callbackAction";
+ private static final String ARG_GROUP_ID = "groupId";
+
+ private static final long NO_GROUP_ID = -1;
+
/** Callbacks for hosts of the {@link GroupNameEditDialogFragment}. */
public interface Listener {
- void onGroupNameEdit(String groupName, boolean isInsert);
+ void onGroupNameEditStarted(String name);
void onGroupNameEditCancelled();
+
+ public static final Listener None = new Listener() {
+ @Override
+ public void onGroupNameEditStarted(String name) { }
+
+ @Override
+ public void onGroupNameEditCancelled() { }
+ };
}
private boolean mIsInsert;
private String mGroupName;
+ private long mGroupId;
+ private Listener mListener;
+ private AccountWithDataSet mAccount;
private EditText mGroupNameEditText;
+ private TextInputLayout mGroupNameTextLayout;
+ private Set<String> mExistingGroups = Collections.emptySet();
- public static void showInsertDialog(FragmentManager fragmentManager, String tag) {
- showDialog(fragmentManager, tag, /* isInsert */ true, /* groupName */ null);
+ public static GroupNameEditDialogFragment newInstanceForCreation(
+ AccountWithDataSet account, String callbackAction) {
+ return newInstance(account, callbackAction, NO_GROUP_ID, null);
}
- public static void showUpdateDialog(FragmentManager fragmentManager,
- String tag, String groupName) {
- showDialog(fragmentManager, tag, /* isInsert */ false, groupName);
+ public static GroupNameEditDialogFragment newInstanceForUpdate(
+ AccountWithDataSet account, String callbackAction, long groupId, String groupName) {
+ return newInstance(account, callbackAction, groupId, groupName);
}
- private static void showDialog(FragmentManager fragmentManager,
- String tag, boolean isInsert, String groupName) {
+ private static GroupNameEditDialogFragment newInstance(
+ AccountWithDataSet account, String callbackAction, long groupId, String groupName) {
+ if (account == null || account.name == null || account.type == null) {
+ throw new IllegalArgumentException("Invalid account");
+ }
+ final boolean isInsert = groupId == NO_GROUP_ID;
final Bundle args = new Bundle();
args.putBoolean(ARG_IS_INSERT, isInsert);
+ args.putLong(ARG_GROUP_ID, groupId);
args.putString(ARG_GROUP_NAME, groupName);
+ args.putParcelable(ARG_ACCOUNT, account);
+ args.putString(ARG_CALLBACK_ACTION, callbackAction);
final GroupNameEditDialogFragment dialog = new GroupNameEditDialogFragment();
dialog.setArguments(args);
- dialog.show(fragmentManager, tag);
+ return dialog;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setStyle(STYLE_NORMAL, R.style.ContactsAlertDialogThemeAppCompat);
+ final Bundle args = getArguments();
if (savedInstanceState == null) {
- final Bundle args = getArguments();
- mIsInsert = args.getBoolean(KEY_IS_INSERT);
mGroupName = args.getString(KEY_GROUP_NAME);
} else {
- mIsInsert = savedInstanceState.getBoolean(ARG_IS_INSERT);
mGroupName = savedInstanceState.getString(ARG_GROUP_NAME);
}
+ mGroupId = args.getLong(ARG_GROUP_ID, NO_GROUP_ID);
+ mIsInsert = args.getBoolean(ARG_IS_INSERT, true);
+ mAccount = getArguments().getParcelable(ARG_ACCOUNT);
+
+ // There is only one loader so the id arg doesn't matter.
+ getLoaderManager().initLoader(0, null, this);
}
@Override
@@ -96,7 +142,7 @@
title.setText(mIsInsert
? R.string.group_name_dialog_insert_title
: R.string.group_name_dialog_update_title);
- final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), getTheme())
.setCustomTitle(title)
.setView(R.layout.group_name_edit_dialog)
.setNegativeButton(android.R.string.cancel, new OnClickListener() {
@@ -107,12 +153,9 @@
dismiss();
}
})
- .setPositiveButton(android.R.string.ok, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- getListener().onGroupNameEdit(getGroupName(), mIsInsert);
- }
- });
+ // The Positive button listener is defined below in the OnShowListener to
+ // allow for input validation
+ .setPositiveButton(android.R.string.ok, null);
// Disable the create button when the name is empty
final AlertDialog alertDialog = builder.create();
@@ -122,6 +165,8 @@
@Override
public void onShow(DialogInterface dialog) {
mGroupNameEditText = (EditText) alertDialog.findViewById(android.R.id.text1);
+ mGroupNameTextLayout =
+ (TextInputLayout) alertDialog.findViewById(R.id.text_input_layout);
if (!TextUtils.isEmpty(mGroupName)) {
mGroupNameEditText.setText(mGroupName);
// Guard against already created group names that are longer than the max
@@ -134,6 +179,14 @@
final Button createButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
createButton.setEnabled(!TextUtils.isEmpty(getGroupName()));
+
+ // Override the click listener to prevent dismissal if creating a duplicate group.
+ createButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ maybePersistCurrentGroupName(v);
+ }
+ });
mGroupNameEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -145,6 +198,7 @@
@Override
public void afterTextChanged(Editable s) {
+ mGroupNameTextLayout.setError(null);
createButton.setEnabled(!TextUtils.isEmpty(s));
}
});
@@ -154,6 +208,56 @@
return alertDialog;
}
+ /**
+ * Sets the listener for the rename
+ *
+ * Setting a listener on a fragment is error prone since it will be lost if the fragment
+ * is recreated. This exists because it is used from a view class (GroupMembersView) which
+ * needs to modify it's state when this fragment updates the name.
+ *
+ * @param listener the listener. can be null
+ */
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ private boolean hasNameChanged() {
+ final String name = Strings.nullToEmpty(getGroupName());
+ final String originalName = getArguments().getString(ARG_GROUP_NAME);
+ return (mIsInsert && !name.isEmpty()) || !name.equals(originalName);
+ }
+
+ private void maybePersistCurrentGroupName(View button) {
+ if (!hasNameChanged()) {
+ dismiss();
+ return;
+ }
+ final String name = getGroupName();
+ // Note we don't check if the loader finished populating mExistingGroups. It's not the
+ // end of the world if the user ends up with a duplicate group and in practice it should
+ // never really happen (the query should complete much sooner than the user can edit the
+ // label)
+ if (mExistingGroups.contains(name)) {
+ mGroupNameTextLayout.setError(
+ getString(R.string.groupExistsErrorMessage));
+ button.setEnabled(false);
+ return;
+ }
+ final String callbackAction = getArguments().getString(ARG_CALLBACK_ACTION);
+ final Intent serviceIntent;
+ if (mIsInsert) {
+ serviceIntent = ContactSaveService.createNewGroupIntent(getActivity(),
+ new AccountWithDataSet(mAccount.name, mAccount.type, mAccount.dataSet),
+ name, null, getActivity().getClass(), callbackAction);
+ } else {
+ serviceIntent = ContactSaveService.createGroupRenameIntent(getActivity(), mGroupId,
+ name, getActivity().getClass(), callbackAction);
+ }
+ ContactSaveService.startService(getActivity(), serviceIntent);
+ getListener().onGroupNameEditStarted(name);
+ dismiss();
+ }
+
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
@@ -163,10 +267,61 @@
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putBoolean(KEY_IS_INSERT, mIsInsert);
outState.putString(KEY_GROUP_NAME, getGroupName());
}
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ // Only a single loader so id is ignored.
+ return new CursorLoader(getActivity(), GroupNameQuery.URI,
+ GroupNameQuery.PROJECTION, GroupNameQuery.getSelection(mAccount),
+ GroupNameQuery.getSelectionArgs(mAccount), null);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ mExistingGroups = new HashSet<>();
+ while (data.moveToNext()) {
+ mExistingGroups.add(data.getString(GroupNameQuery.TITLE));
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ }
+
+ /**
+ * Defines the structure of the query performed by the CursorLoader created by
+ * GroupNameEditDialogFragment
+ */
+ private static class GroupNameQuery {
+
+ public static final int TITLE = 0;
+ public static final Uri URI = ContactsContract.Groups.CONTENT_URI;
+ public static final String[] PROJECTION = new String[] { ContactsContract.Groups.TITLE };
+
+ public static String getSelection(AccountWithDataSet account) {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(ContactsContract.Groups.ACCOUNT_NAME).append("=? AND ")
+ .append(ContactsContract.Groups.ACCOUNT_TYPE).append("=?");
+ if (account.dataSet != null) {
+ builder.append(" AND ").append(ContactsContract.Groups.DATA_SET).append("=?");
+ }
+ return builder.toString();
+ }
+
+ public static String[] getSelectionArgs(AccountWithDataSet account) {
+ final int len = account.dataSet == null ? 2 : 3;
+ final String[] args = new String[len];
+ args[0] = account.name;
+ args[1] = account.type;
+ if (account.dataSet != null) {
+ args[2] = account.dataSet;
+ }
+ return args;
+ }
+ }
+
private void showInputMethod(View view) {
final InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
Context.INPUT_METHOD_SERVICE);
@@ -184,11 +339,13 @@
}
private Listener getListener() {
- if (!(getActivity() instanceof Listener)) {
- throw new ClassCastException(getActivity() + " must implement " +
- Listener.class.getName());
+ if (mListener != null) {
+ return mListener;
+ } else if (getActivity() instanceof Listener) {
+ return (Listener) getActivity();
+ } else {
+ return Listener.None;
}
- return (Listener) getActivity();
}
private String getGroupName() {
diff --git a/src/com/android/contacts/group/GroupsFragment.java b/src/com/android/contacts/group/GroupsFragment.java
index be1b44a..508c184 100644
--- a/src/com/android/contacts/group/GroupsFragment.java
+++ b/src/com/android/contacts/group/GroupsFragment.java
@@ -18,7 +18,6 @@
import android.app.Fragment;
import android.app.LoaderManager;
-import android.content.Context;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
diff --git a/src/com/android/contacts/interactions/CallLogInteraction.java b/src/com/android/contacts/interactions/CallLogInteraction.java
index 3464c0f..06fd273 100644
--- a/src/com/android/contacts/interactions/CallLogInteraction.java
+++ b/src/com/android/contacts/interactions/CallLogInteraction.java
@@ -87,9 +87,18 @@
@Override
public String getViewFooter(Context context) {
- Long date = getDate();
- return date == null ? null : ContactInteractionUtil.formatDateStringFromTimestamp(
- date, context);
+ final Long date = getDate();
+ if (date != null) {
+ final StringBuilder callDetail = new StringBuilder();
+ callDetail.append(ContactInteractionUtil.formatDateStringFromTimestamp(date, context));
+ final Long duration = getDuration();
+ if (duration != null) {
+ callDetail.append("\n");
+ callDetail.append(ContactInteractionUtil.formatDuration(duration, context));
+ }
+ return callDetail.toString();
+ }
+ return null;
}
@Override
diff --git a/src/com/android/contacts/interactions/ContactInteractionUtil.java b/src/com/android/contacts/interactions/ContactInteractionUtil.java
index 98d45ee..b2bda5d 100644
--- a/src/com/android/contacts/interactions/ContactInteractionUtil.java
+++ b/src/com/android/contacts/interactions/ContactInteractionUtil.java
@@ -28,7 +28,6 @@
import com.android.contacts.R;
-
/**
* Utility methods for interactions and their loaders
*/
@@ -61,8 +60,7 @@
* compareCalendar.
* This formats the date based on a few conditions:
* 1. If the timestamp is today, the time is shown
- * 2. If the timestamp occurs tomorrow or yesterday, that is displayed
- * 3. Otherwise {Month Date} format is used
+ * 2. Otherwise show full date and time
*/
@NeededForTesting
public static String formatDateStringFromTimestamp(long timestamp, Context context,
@@ -76,19 +74,9 @@
interactionCalendar.getTime());
}
- // Turn compareCalendar to yesterday
- compareCalendar.add(Calendar.DAY_OF_YEAR, -1);
- if (compareCalendarDayYear(interactionCalendar, compareCalendar)) {
- return context.getString(R.string.yesterday);
- }
-
- // Turn compareCalendar to tomorrow
- compareCalendar.add(Calendar.DAY_OF_YEAR, 2);
- if (compareCalendarDayYear(interactionCalendar, compareCalendar)) {
- return context.getString(R.string.tomorrow);
- }
- return DateUtils.formatDateTime(context, interactionCalendar.getTimeInMillis(),
- DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR);
+ return DateUtils.formatDateTime(context, timestamp, DateUtils.FORMAT_SHOW_TIME
+ | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY
+ | DateUtils.FORMAT_SHOW_YEAR);
}
/**
@@ -98,4 +86,23 @@
return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR) &&
c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR);
}
+
+ /**
+ * Takes duration of the call in seconds.
+ * Return the formatted duration in hr, min, sec order if they exist.
+ */
+ @NeededForTesting
+ public static String formatDuration(long callDuration, Context context) {
+ final int hours = (int) callDuration / 3600;
+ final int minutes = (int) (callDuration % 3600) / 60;
+ final int seconds = (int) (callDuration % 60);
+
+ if (hours > 0) {
+ return context.getString(R.string.callDurationHourFormat, hours, minutes, seconds);
+ } else if (minutes > 0) {
+ return context.getString(R.string.callDurationMinuteFormat, minutes, seconds);
+ } else {
+ return context.getString(R.string.callDurationSecondFormat, seconds);
+ }
+ }
}
diff --git a/src/com/android/contacts/interactions/GroupCreationDialogFragment.java b/src/com/android/contacts/interactions/GroupCreationDialogFragment.java
deleted file mode 100644
index e998688..0000000
--- a/src/com/android/contacts/interactions/GroupCreationDialogFragment.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2010 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.interactions;
-
-import android.app.Activity;
-import android.app.FragmentManager;
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.EditText;
-
-import com.android.contacts.ContactSaveService;
-import com.android.contacts.R;
-import com.android.contacts.activities.ContactEditorBaseActivity;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-
-/**
- * A dialog for creating a new group.
- */
-public class GroupCreationDialogFragment extends GroupNameDialogFragment {
- private static final String ARG_ACCOUNT_TYPE = "accountType";
- private static final String ARG_ACCOUNT_NAME = "accountName";
- private static final String ARG_DATA_SET = "dataSet";
-
- public static final String FRAGMENT_TAG = "createGroupDialog";
-
- private final OnGroupCreatedListener mListener;
-
- public interface OnGroupCreatedListener {
- public void onGroupCreated();
- }
-
- public static void show(
- FragmentManager fragmentManager, String accountType, String accountName,
- String dataSet, OnGroupCreatedListener listener) {
- GroupCreationDialogFragment dialog = new GroupCreationDialogFragment(listener);
- Bundle args = new Bundle();
- args.putString(ARG_ACCOUNT_TYPE, accountType);
- args.putString(ARG_ACCOUNT_NAME, accountName);
- args.putString(ARG_DATA_SET, dataSet);
- dialog.setArguments(args);
- dialog.show(fragmentManager, FRAGMENT_TAG);
- }
-
- public GroupCreationDialogFragment() {
- super();
- mListener = null;
- }
-
- private GroupCreationDialogFragment(OnGroupCreatedListener listener) {
- super();
- mListener = listener;
- }
-
- public OnGroupCreatedListener getOnGroupCreatedListener() {
- return mListener;
- }
-
- @Override
- protected void initializeGroupLabelEditText(EditText editText) {
- }
-
- @Override
- protected int getTitleResourceId() {
- return R.string.create_group_dialog_title;
- }
-
- @Override
- protected void onCompleted(String groupLabel) {
- Bundle arguments = getArguments();
- String accountType = arguments.getString(ARG_ACCOUNT_TYPE);
- String accountName = arguments.getString(ARG_ACCOUNT_NAME);
- String dataSet = arguments.getString(ARG_DATA_SET);
-
- // Indicate to the listener that a new group will be created.
- // If the device is rotated, mListener will become null, so that the
- // popup from GroupMembershipView will not be shown.
- if (mListener != null) {
- mListener.onGroupCreated();
- }
-
- Activity activity = getActivity();
- activity.startService(ContactSaveService.createNewGroupIntent(activity,
- new AccountWithDataSet(accountName, accountType, dataSet), groupLabel,
- null /* no new members to add */,
- activity.getClass(), ContactEditorBaseActivity.ACTION_EDIT));
- }
-}
diff --git a/src/com/android/contacts/interactions/GroupNameDialogFragment.java b/src/com/android/contacts/interactions/GroupNameDialogFragment.java
deleted file mode 100644
index 5efccfc..0000000
--- a/src/com/android/contacts/interactions/GroupNameDialogFragment.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2010 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.interactions;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnShowListener;
-import android.os.Bundle;
-import android.text.Editable;
-import android.text.InputFilter;
-import android.text.InputType;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.EditText;
-
-import com.android.contacts.R;
-
-/**
- * A common superclass for creating and renaming groups.
- */
-// TODO: consolidate it with GroupNameEditDialogFragment
-public abstract class GroupNameDialogFragment extends DialogFragment {
- protected abstract int getTitleResourceId();
- protected abstract void initializeGroupLabelEditText(EditText editText);
- protected abstract void onCompleted(String groupLabel);
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- final LayoutInflater layoutInflater = LayoutInflater.from(builder.getContext());
- final View view = layoutInflater.inflate(R.layout.group_name_dialog, null);
- final EditText editText = (EditText) view.findViewById(R.id.group_label);
- final int maxLength = getResources().getInteger(R.integer.group_name_max_length);
- editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(maxLength) });
- editText.setInputType(InputType.TYPE_CLASS_TEXT);
- initializeGroupLabelEditText(editText);
-
- builder.setTitle(getTitleResourceId());
- builder.setView(view);
- editText.requestFocus();
- builder.setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int whichButton) {
- onCompleted(editText.getText().toString().trim());
- }
- }
- );
-
- builder.setNegativeButton(android.R.string.cancel, null);
- final AlertDialog dialog = builder.create();
-
- dialog.setOnShowListener(new OnShowListener() {
- @Override
- public void onShow(DialogInterface dialogInterface) {
- updateOkButtonState(dialog, editText);
- }
- });
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- updateOkButtonState(dialog, editText);
- }
- });
- dialog.getWindow().setSoftInputMode(
- WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
- return dialog;
- }
-
- /* package */ void updateOkButtonState(AlertDialog dialog, EditText editText) {
- final Button okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
- okButton.setEnabled(!TextUtils.isEmpty(editText.getText().toString().trim()));
- }
-}
diff --git a/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java b/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
index db6d80a..da017cc 100644
--- a/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
+++ b/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
@@ -497,12 +497,12 @@
if (TextUtils.isEmpty(mTitleTextView.getText()) &&
entriesViewGroup.size() > 0) {
final View entry = entriesViewGroup.get(0);
- entry.setPadding(entry.getPaddingLeft(),
+ entry.setPaddingRelative(entry.getPaddingStart(),
getResources().getDimensionPixelSize(
R.dimen.expanding_entry_card_item_padding_top) +
getResources().getDimensionPixelSize(
R.dimen.expanding_entry_card_null_title_top_extra_padding),
- entry.getPaddingRight(),
+ entry.getPaddingEnd(),
entry.getPaddingBottom());
}
}
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index e918233..c595f23 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -239,7 +239,6 @@
private static final String MIMETYPE_GPLUS_PROFILE =
"vnd.android.cursor.item/vnd.googleplus.profile";
- private static final String GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE = "addtocircle";
private static final String GPLUS_PROFILE_DATA_5_VIEW_PROFILE = "view";
private static final String MIMETYPE_HANGOUTS =
"vnd.android.cursor.item/vnd.googleplus.profile.comm";
@@ -2108,30 +2107,7 @@
// Build advanced entry for known 3p types. Otherwise default to ResolveCache icon.
switch (mimetype) {
case MIMETYPE_GPLUS_PROFILE:
- // If a secondDataItem is available, use it to build an entry with
- // alternate actions
- if (secondDataItem != null) {
- icon = res.getDrawable(R.drawable.ic_google_plus_black_24dp);
- alternateIcon = res.getDrawable(R.drawable.ic_add_to_circles_black_24);
- final GPlusOrHangoutsDataItemModel itemModel =
- new GPlusOrHangoutsDataItemModel(intent, alternateIntent,
- dataItem, secondDataItem, alternateContentDescription,
- header, text, context);
-
- populateGPlusOrHangoutsDataItemModel(itemModel);
- intent = itemModel.intent;
- alternateIntent = itemModel.alternateIntent;
- alternateContentDescription = itemModel.alternateContentDescription;
- header = itemModel.header;
- text = itemModel.text;
- } else {
- if (GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE.equals(
- intent.getDataString())) {
- icon = res.getDrawable(R.drawable.ic_add_to_circles_black_24);
- } else {
- icon = res.getDrawable(R.drawable.ic_google_plus_black_24dp);
- }
- }
+ icon = res.getDrawable(R.drawable.ic_google_plus_black_24dp);
break;
case MIMETYPE_HANGOUTS:
// If a secondDataItem is available, use it to build an entry with
@@ -2139,12 +2115,12 @@
if (secondDataItem != null) {
icon = res.getDrawable(R.drawable.ic_hangout_24dp);
alternateIcon = res.getDrawable(R.drawable.ic_hangout_video_24dp);
- final GPlusOrHangoutsDataItemModel itemModel =
- new GPlusOrHangoutsDataItemModel(intent, alternateIntent,
+ final HangoutsDataItemModel itemModel =
+ new HangoutsDataItemModel(intent, alternateIntent,
dataItem, secondDataItem, alternateContentDescription,
header, text, context);
- populateGPlusOrHangoutsDataItemModel(itemModel);
+ populateHangoutsDataItemModel(itemModel);
intent = itemModel.intent;
alternateIntent = itemModel.alternateIntent;
alternateContentDescription = itemModel.alternateContentDescription;
@@ -2216,9 +2192,10 @@
private List<Entry> dataItemsToEntries(List<DataItem> dataItems,
MutableString aboutCardTitleOut) {
// Hangouts and G+ use two data items to create one entry.
- if (dataItems.get(0).getMimeType().equals(MIMETYPE_GPLUS_PROFILE) ||
- dataItems.get(0).getMimeType().equals(MIMETYPE_HANGOUTS)) {
- return gPlusOrHangoutsDataItemsToEntries(dataItems);
+ if (dataItems.get(0).getMimeType().equals(MIMETYPE_GPLUS_PROFILE)) {
+ return gPlusDataItemsToEntries(dataItems);
+ } else if (dataItems.get(0).getMimeType().equals(MIMETYPE_HANGOUTS)) {
+ return hangoutsDataItemsToEntries(dataItems);
} else {
final List<Entry> entries = new ArrayList<>();
for (DataItem dataItem : dataItems) {
@@ -2233,15 +2210,10 @@
}
/**
- * G+ and Hangout entries are unique in that a single ExpandingEntryCardView.Entry consists
- * of two data items. This method attempts to build each entry using the two data items if
- * they are available. If there are more or less than two data items, a fall back is used
- * and each data item gets its own entry.
+ * Put the data items into buckets based on the raw contact id
*/
- private List<Entry> gPlusOrHangoutsDataItemsToEntries(List<DataItem> dataItems) {
- final List<Entry> entries = new ArrayList<>();
+ private Map<Long, List<DataItem>> dataItemsToBucket(List<DataItem> dataItems) {
final Map<Long, List<DataItem>> buckets = new HashMap<>();
- // Put the data items into buckets based on the raw contact id
for (DataItem dataItem : dataItems) {
List<DataItem> bucket = buckets.get(dataItem.getRawContactId());
if (bucket == null) {
@@ -2250,10 +2222,43 @@
}
bucket.add(dataItem);
}
+ return buckets;
+ }
+
+ /**
+ * For G+ entries, a single ExpandingEntryCardView.Entry consists of two data items. This
+ * method use only the View profile to build entry.
+ */
+ private List<Entry> gPlusDataItemsToEntries(List<DataItem> dataItems) {
+ final List<Entry> entries = new ArrayList<>();
+
+ for (List<DataItem> bucket : dataItemsToBucket(dataItems).values()) {
+ for (DataItem dataItem : bucket) {
+ if (GPLUS_PROFILE_DATA_5_VIEW_PROFILE.equals(
+ dataItem.getContentValues().getAsString(Data.DATA5))) {
+ final Entry entry = dataItemToEntry(dataItem, /* secondDataItem = */ null,
+ this, mContactData, /* aboutCardName = */ null);
+ if (entry != null) {
+ entries.add(entry);
+ }
+ }
+ }
+ }
+ return entries;
+ }
+
+ /**
+ * For Hangouts entries, a single ExpandingEntryCardView.Entry consists of two data items. This
+ * method attempts to build each entry using the two data items if they are available. If there
+ * are more or less than two data items, a fall back is used and each data item gets its own
+ * entry.
+ */
+ private List<Entry> hangoutsDataItemsToEntries(List<DataItem> dataItems) {
+ final List<Entry> entries = new ArrayList<>();
// Use the buckets to build entries. If a bucket contains two data items, build the special
// entry, otherwise fall back to the normal entry.
- for (List<DataItem> bucket : buckets.values()) {
+ for (List<DataItem> bucket : dataItemsToBucket(dataItems).values()) {
if (bucket.size() == 2) {
// Use the pair to build an entry
final Entry entry = dataItemToEntry(bucket.get(0),
@@ -2276,10 +2281,10 @@
}
/**
- * Used for statically passing around G+ or Hangouts data items and entry fields to
- * populateGPlusOrHangoutsDataItemModel.
+ * Used for statically passing around Hangouts data items and entry fields to
+ * populateHangoutsDataItemModel.
*/
- private static final class GPlusOrHangoutsDataItemModel {
+ private static final class HangoutsDataItemModel {
public Intent intent;
public Intent alternateIntent;
public DataItem dataItem;
@@ -2289,7 +2294,7 @@
public String text;
public Context context;
- public GPlusOrHangoutsDataItemModel(Intent intent, Intent alternateIntent, DataItem dataItem,
+ public HangoutsDataItemModel(Intent intent, Intent alternateIntent, DataItem dataItem,
DataItem secondDataItem, StringBuilder alternateContentDescription, String header,
String text, Context context) {
this.intent = intent;
@@ -2303,18 +2308,16 @@
}
}
- private static void populateGPlusOrHangoutsDataItemModel(
- GPlusOrHangoutsDataItemModel dataModel) {
+ private static void populateHangoutsDataItemModel(
+ HangoutsDataItemModel dataModel) {
final Intent secondIntent = new Intent(Intent.ACTION_VIEW);
secondIntent.setDataAndType(ContentUris.withAppendedId(Data.CONTENT_URI,
dataModel.secondDataItem.getId()), dataModel.secondDataItem.getMimeType());
// There is no guarantee the order the data items come in. Second
// data item does not necessarily mean it's the alternate.
- // Hangouts video and Add to circles should be alternate. Swap if needed
+ // Hangouts video should be alternate. Swap if needed
if (HANGOUTS_DATA_5_VIDEO.equals(
- dataModel.dataItem.getContentValues().getAsString(Data.DATA5)) ||
- GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE.equals(
- dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
+ dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
dataModel.alternateIntent = dataModel.intent;
dataModel.alternateContentDescription = new StringBuilder(dataModel.header);
@@ -2323,9 +2326,7 @@
dataModel.secondDataItem.getDataKind());
dataModel.text = dataModel.secondDataItem.getDataKind().typeColumn;
} else if (HANGOUTS_DATA_5_MESSAGE.equals(
- dataModel.dataItem.getContentValues().getAsString(Data.DATA5)) ||
- GPLUS_PROFILE_DATA_5_VIEW_PROFILE.equals(
- dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
+ dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
dataModel.alternateIntent = secondIntent;
dataModel.alternateContentDescription = new StringBuilder(
dataModel.secondDataItem.buildDataStringForDisplay(dataModel.context,
diff --git a/tests/Android.mk b/tests/Android.mk
index 4fd947c..48a00f4 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -7,11 +7,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
-src_dirs := src \
- ../../ContactsCommon/TestCommon/src
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, res)
LOCAL_PACKAGE_NAME := ContactsTests
@@ -20,4 +17,11 @@
LOCAL_SDK_VERSION := current
LOCAL_MIN_SDK_VERSION := 21
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ mockito-target
+
+LOCAL_AAPT_FLAGS := \
+ --auto-add-overlay \
+ --extra-packages com.android.contacts.common.tests
+
include $(BUILD_PACKAGE)
diff --git a/tests/res/values/donottranslate_strings.xml b/tests/res/values/donottranslate_strings.xml
index 8f43dbf..1528112 100644
--- a/tests/res/values/donottranslate_strings.xml
+++ b/tests/res/values/donottranslate_strings.xml
@@ -105,4 +105,6 @@
<string name="attribution_twitter">Twitter</string>
<string name="authenticator_basic_label">Test adapter</string>
+
+ <string name="test_string">TEST STRING</string>
</resources>
diff --git a/tests/res/xml/contacts_fallback.xml b/tests/res/xml/contacts_fallback.xml
new file mode 100644
index 0000000..7034d5e
--- /dev/null
+++ b/tests/res/xml/contacts_fallback.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!--
+ contacts.xml to build "fallback account type" equivalent.
+ This is directly used in ExternalAccountTypeTest to test the parser. There's no sync adapter
+ that actually defined with this definition.
+-->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema
+ >
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsDisplayName="true"
+ supportsPrefix="true"
+ supportsMiddleName="true"
+ supportsSuffix="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticMiddleName="true"
+ supportsPhoneticGivenName="true"
+ >
+ </DataKind>
+ <DataKind kind="photo" maxOccurs="1" />
+ <DataKind kind="phone" >
+ <Type type="mobile" />
+ <Type type="home" />
+ <Type type="work" />
+ <Type type="fax_work" />
+ <Type type="fax_home" />
+ <Type type="pager" />
+ <Type type="other" />
+ <Type type="custom"/>
+ <Type type="callback" />
+ <Type type="car" />
+ <Type type="company_main" />
+ <Type type="isdn" />
+ <Type type="main" />
+ <Type type="other_fax" />
+ <Type type="radio" />
+ <Type type="telex" />
+ <Type type="tty_tdd" />
+ <Type type="work_mobile"/>
+ <Type type="work_pager" />
+ <Type type="assistant" />
+ <Type type="mms" />
+ </DataKind>
+ <DataKind kind="email" >
+ <Type type="home" />
+ <Type type="work" />
+ <Type type="other" />
+ <Type type="mobile" />
+ <Type type="custom" />
+ </DataKind>
+ <DataKind kind="nickname" maxOccurs="1" />
+ <DataKind kind="im" >
+ <Type type="aim" />
+ <Type type="msn" />
+ <Type type="yahoo" />
+ <Type type="skype" />
+ <Type type="qq" />
+ <Type type="google_talk" />
+ <Type type="icq" />
+ <Type type="jabber" />
+ <Type type="custom" />
+ </DataKind>
+ <DataKind kind="postal" needsStructured="false" >
+ <Type type="home" />
+ <Type type="work" />
+ <Type type="other" />
+ <Type type="custom" />
+ </DataKind>
+ <DataKind kind="organization" maxOccurs="1" />
+ <DataKind kind="website" />
+ <DataKind kind="sip_address" maxOccurs="1" />
+ <DataKind kind="note" maxOccurs="1" />
+ <DataKind kind="group_membership" maxOccurs="1" />
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/contacts_readonly.xml b/tests/res/xml/contacts_readonly.xml
new file mode 100644
index 0000000..df8d9c0
--- /dev/null
+++ b/tests/res/xml/contacts_readonly.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!--
+ Contacts.xml without EditSchema.
+-->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <ContactsDataKind
+ android:icon="@drawable/android"
+ android:mimeType="vnd.android.cursor.item/a.b.c"
+ android:summaryColumn="data1"
+ android:detailColumn="data2"
+ android:detailSocialSummary="true"
+ >
+ </ContactsDataKind>
+ <ContactsDataKind
+ android:icon="@drawable/default_icon"
+ android:mimeType="vnd.android.cursor.item/d.e.f"
+ android:summaryColumn="data3"
+ android:detailColumn="data4"
+ android:detailSocialSummary="false"
+ >
+ </ContactsDataKind>
+ <ContactsDataKind
+ android:icon="@drawable/android"
+ android:mimeType="vnd.android.cursor.item/xyz"
+ android:summaryColumn="data5"
+ android:detailColumn="data6"
+ android:detailSocialSummary="true"
+ >
+ </ContactsDataKind>
+</ContactsAccountType>
diff --git a/tests/res/xml/iconset.xml b/tests/res/xml/iconset.xml
index b9e419d..d1207e7 100644
--- a/tests/res/xml/iconset.xml
+++ b/tests/res/xml/iconset.xml
@@ -1,25 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2012 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
- -->
+<!-- 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.
+-->
<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"
+ <icon android:mimeType="vnd.android.cursor.item/phone"
android:icon="@drawable/phone_icon" />
-</icon-set>
+</icon-set>
\ No newline at end of file
diff --git a/tests/res/xml/missing_contacts_base.xml b/tests/res/xml/missing_contacts_base.xml
new file mode 100644
index 0000000..2c9aa6d
--- /dev/null
+++ b/tests/res/xml/missing_contacts_base.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- XML for must-have checks. Base definition, which is valid. -->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema>
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsDisplayName="true"
+ supportsPrefix="true"
+ supportsMiddleName="true"
+ supportsSuffix="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticMiddleName="true"
+ supportsPhoneticGivenName="true"
+ >
+ </DataKind>
+ <DataKind kind="photo" maxOccurs="1" />
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/missing_contacts_name.xml b/tests/res/xml/missing_contacts_name.xml
new file mode 100644
index 0000000..1ac26be
--- /dev/null
+++ b/tests/res/xml/missing_contacts_name.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- XML for must-have checks. Missing "name" kind. -->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema>
+ <DataKind kind="photo" maxOccurs="1" />
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/missing_contacts_name_attr1.xml b/tests/res/xml/missing_contacts_name_attr1.xml
new file mode 100644
index 0000000..b7b0f19
--- /dev/null
+++ b/tests/res/xml/missing_contacts_name_attr1.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- XML for must-have checks. Missing one of the "support*" attributes". -->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema>
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsPrefix="true"
+ supportsMiddleName="true"
+ supportsSuffix="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticMiddleName="true"
+ supportsPhoneticGivenName="true"
+ />
+ <DataKind kind="photo" maxOccurs="1" />
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/missing_contacts_name_attr2.xml b/tests/res/xml/missing_contacts_name_attr2.xml
new file mode 100644
index 0000000..41be9e8
--- /dev/null
+++ b/tests/res/xml/missing_contacts_name_attr2.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- XML for must-have checks. Missing one of the "support*" attributes". -->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema>
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsDisplayName="true"
+ supportsMiddleName="true"
+ supportsSuffix="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticMiddleName="true"
+ supportsPhoneticGivenName="true"
+ />
+ <DataKind kind="photo" maxOccurs="1" />
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/missing_contacts_name_attr3.xml b/tests/res/xml/missing_contacts_name_attr3.xml
new file mode 100644
index 0000000..e639a76
--- /dev/null
+++ b/tests/res/xml/missing_contacts_name_attr3.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- XML for must-have checks. Missing one of the "support*" attributes". -->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema>
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsDisplayName="true"
+ supportsPrefix="true"
+ supportsSuffix="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticMiddleName="true"
+ supportsPhoneticGivenName="true"
+ />
+ <DataKind kind="photo" maxOccurs="1" />
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/missing_contacts_name_attr4.xml b/tests/res/xml/missing_contacts_name_attr4.xml
new file mode 100644
index 0000000..b42cdcd
--- /dev/null
+++ b/tests/res/xml/missing_contacts_name_attr4.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- XML for must-have checks. Missing one of the "support*" attributes". -->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema>
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsDisplayName="true"
+ supportsPrefix="true"
+ supportsMiddleName="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticMiddleName="true"
+ supportsPhoneticGivenName="true"
+ />
+ <DataKind kind="photo" maxOccurs="1" />
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/missing_contacts_name_attr5.xml b/tests/res/xml/missing_contacts_name_attr5.xml
new file mode 100644
index 0000000..3778d2f
--- /dev/null
+++ b/tests/res/xml/missing_contacts_name_attr5.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- XML for must-have checks. Missing one of the "support*" attributes". -->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema>
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsDisplayName="true"
+ supportsPrefix="true"
+ supportsMiddleName="true"
+ supportsSuffix="true"
+ supportsPhoneticMiddleName="true"
+ supportsPhoneticGivenName="true"
+ />
+ <DataKind kind="photo" maxOccurs="1" />
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/missing_contacts_name_attr6.xml b/tests/res/xml/missing_contacts_name_attr6.xml
new file mode 100644
index 0000000..b3a3411
--- /dev/null
+++ b/tests/res/xml/missing_contacts_name_attr6.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- XML for must-have checks. Missing one of the "support*" attributes". -->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema>
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsDisplayName="true"
+ supportsPrefix="true"
+ supportsMiddleName="true"
+ supportsSuffix="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticGivenName="true"
+ />
+ <DataKind kind="photo" maxOccurs="1" />
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/missing_contacts_name_attr7.xml b/tests/res/xml/missing_contacts_name_attr7.xml
new file mode 100644
index 0000000..c87e4f1
--- /dev/null
+++ b/tests/res/xml/missing_contacts_name_attr7.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- XML for must-have checks. Missing one of the "support*" attributes". -->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema>
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsDisplayName="true"
+ supportsPrefix="true"
+ supportsMiddleName="true"
+ supportsSuffix="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticMiddleName="true"
+ />
+ <DataKind kind="photo" maxOccurs="1" />
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/missing_contacts_photo.xml b/tests/res/xml/missing_contacts_photo.xml
new file mode 100644
index 0000000..87f4fc6
--- /dev/null
+++ b/tests/res/xml/missing_contacts_photo.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- XML for must-have checks. Missing "photo" kind. -->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema>
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsDisplayName="true"
+ supportsPrefix="true"
+ supportsMiddleName="true"
+ supportsSuffix="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticMiddleName="true"
+ supportsPhoneticGivenName="true"
+ >
+ </DataKind>
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/test_basic_contacts.xml b/tests/res/xml/test_basic_contacts.xml
new file mode 100644
index 0000000..0047204
--- /dev/null
+++ b/tests/res/xml/test_basic_contacts.xml
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<ContactsAccountType
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ >
+ <EditSchema
+ >
+ <!--
+ Name:
+ - maxOccurs must be 1
+ - No types.
+
+ - Currently all the supportsXxx attributes must be true, but here's the plan for the
+ future:
+ (There's some hardcoded assumptions in the contact editor, which is one reason
+ for the above restriction)
+
+ - "Family name" and "Given name" must be supported.
+ - All sync adapters must support structured name. "display name only" is not
+ supported.
+ -> Supporting this would require relatively large changes to
+ the contact editor.
+
+ - Fields are decided from the attributes:
+ StructuredName.DISPLAY_NAME if supportsDisplayName == true
+ StructuredName.PREFIX if supportsPrefix == true
+ StructuredName.FAMILY_NAME (always)
+ StructuredName.MIDDLE_NAME if supportsPrefix == true
+ StructuredName.GIVEN_NAME (always)
+ StructuredName.SUFFIX if supportsSuffix == true
+ StructuredName.PHONETIC_FAMILY_NAME if supportsPhoneticFamilyName == true
+ StructuredName.PHONETIC_MIDDLE_NAME if supportsPhoneticMiddleName == true
+ StructuredName.PHONETIC_GIVEN_NAME if supportsPhoneticGivenName == true
+
+ - DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME is always added.
+ - DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME is added
+ if any of supportsPhoneticXxx == true
+ -->
+ <!-- Fallback/Google definition. Supports all. -->
+ <DataKind kind="name"
+ maxOccurs="1"
+ supportsDisplayName="true"
+ supportsPrefix="true"
+ supportsMiddleName="true"
+ supportsSuffix="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticMiddleName="true"
+ supportsPhoneticGivenName="true"
+ >
+ </DataKind>
+
+ <!-- Exchange definition. No display-name, no phonetic-middle.
+ <DataKind kind="name"
+ supportsDisplayName="false"
+ supportsPrefix="true"
+ supportsMiddleName="true"
+ supportsSuffix="true"
+ supportsPhoneticFamilyName="true"
+ supportsPhoneticMiddleName="false"
+ supportsPhoneticGivenName ="true"
+ >
+ </DataKind>
+ -->
+
+ <!--
+ Photo:
+ - maxOccurs must be 1
+ - No types.
+ -->
+ <DataKind kind="photo" maxOccurs="1" />
+
+ <!--
+ Phone definition.
+ - "is secondary?" is inferred from type.
+ -->
+ <!-- Fallback, Google definition. -->
+ <DataKind kind="phone" >
+ <!-- Note: Google type doesn't have obsolete ones -->
+ <Type type="mobile" />
+ <Type type="home" />
+ <Type type="work" />
+ <Type type="fax_work" />
+ <Type type="fax_home" />
+ <Type type="pager" />
+ <Type type="other" />
+ <Type type="custom"/>
+ <Type type="callback" />
+ <Type type="car" />
+ <Type type="company_main" />
+ <Type type="isdn" />
+ <Type type="main" />
+ <Type type="other_fax" />
+ <Type type="radio" />
+ <Type type="telex" />
+ <Type type="tty_tdd" />
+ <Type type="work_mobile"/>
+ <Type type="work_pager" />
+ <Type type="assistant" />
+ <Type type="mms" />
+ </DataKind>
+
+ <!-- Exchange definition.
+ <DataKind kind="phone" >
+ <Type type="home" maxOccurs="2" />
+ <Type type="mobile" maxOccurs="1" />
+ <Type type="work" maxOccurs="2" />
+ <Type type="fax_work" maxOccurs="1" />
+ <Type type="fax_home" maxOccurs="1" />
+ <Type type="pager" maxOccurs="1" />
+ <Type type="car" maxOccurs="1" />
+ <Type type="company_main" maxOccurs="1" />
+ <Type type="mms" maxOccurs="1" />
+ <Type type="radio" maxOccurs="1" />
+ <Type type="assistant" maxOccurs="1" />
+ </DataKind>
+ -->
+
+ <!--
+ Email
+ -->
+ <!-- Fallback/Google definition. -->
+ <DataKind kind="email" >
+ <!-- Note: Google type doesn't have obsolete ones -->
+ <Type type="home" />
+ <Type type="work" />
+ <Type type="other" />
+ <Type type="mobile" />
+ <Type type="custom" />
+ </DataKind>
+
+ <!--
+ Exchange definition.
+ - Same definition as "fallback" except for maxOccurs=3
+ <DataKind kind="email" maxOccurs="3" >
+ <Type type="home" />
+ <Type type="work" />
+ <Type type="other" />
+ <Type type="mobile" />
+ <Type type="custom" />
+ </DataKind>
+ -->
+
+ <!--
+ Nickname
+ - maxOccurs must be 1
+ - No types.
+ -->
+ <DataKind kind="nickname" maxOccurs="1" />
+
+ <!--
+ Im:
+ - The TYPE column always stores Im.TYPE_OTHER (defaultValues is always set)
+ - The user-selected type is stored in Im.PROTOCOL
+ -->
+ <!-- Fallback, Google definition. -->
+ <DataKind kind="im" >
+ <Type type="aim" />
+ <Type type="msn" />
+ <Type type="yahoo" />
+ <Type type="skype" />
+ <Type type="qq" />
+ <Type type="google_talk" />
+ <Type type="icq" />
+ <Type type="jabber" />
+ <Type type="custom" />
+ </DataKind>
+
+ <!-- Exchange definition.
+ <DataKind kind="im" maxOccurs="3" >
+ <Type type="aim" />
+ <Type type="msn" />
+ <Type type="yahoo" />
+ <Type type="skype" />
+ <Type type="qq" />
+ <Type type="google_talk" />
+ <Type type="icq" />
+ <Type type="jabber" />
+ <Type type="custom" />
+ </DataKind>
+ -->
+
+ <!--
+ Postal address.
+ -->
+ <!-- Fallback/Google definition. Not structured. -->
+ <DataKind kind="postal" needsStructured="false" >
+ <Type type="home" />
+ <Type type="work" />
+ <Type type="other" />
+ <Type type="custom" />
+ </DataKind>
+
+ <!-- Exchange definition. Structured.
+ <DataKind kind="postal" needsStructured="true" >
+ <Type type="work" />
+ <Type type="home" />
+ <Type type="other" />
+ </DataKind>
+ -->
+
+ <!--
+ Organization:
+ - Fields are fixed: COMPANY, TITLE
+ - maxOccurs must be 1
+ - No types.
+ -->
+ <DataKind kind="organization" maxOccurs="1" />
+
+ <!--
+ Website:
+ - No types.
+ -->
+ <DataKind kind="website" />
+
+ <!--
+ Below kinds have nothing configurable.
+ - No types are supported.
+ - maxOccurs must be 1
+ -->
+ <DataKind kind="sip_address" maxOccurs="1" />
+ <DataKind kind="note" maxOccurs="1" />
+
+ <!--
+ Google/Exchange supports it, but fallback doesn't.
+ <DataKind kind="group_membership" maxOccurs="1" />
+ -->
+
+ <!--
+ Event
+ -->
+ <DataKind kind="event" dateWithTime="false">
+ <Type type="birthday" maxOccurs="1" yearOptional="true" />
+ <Type type="anniversary" />
+ <Type type="other" />
+ <Type type="custom" />
+ </DataKind>
+
+ <!--
+ Exchange definition. dateWithTime is needed only for Exchange.
+ <DataKind kind="event" dateWithTime="true">
+ <Type type="birthday" maxOccurs="1" />
+ </DataKind>
+ -->
+
+ <!--
+ Relationship
+ -->
+ <DataKind kind="relationship" >
+ <Type type="assistant" />
+ <Type type="brother" />
+ <Type type="child" />
+ <Type type="domestic_partner" />
+ <Type type="father" />
+ <Type type="friend" />
+ <Type type="manager" />
+ <Type type="mother" />
+ <Type type="parent" />
+ <Type type="partner" />
+ <Type type="referred_by" />
+ <Type type="relative" />
+ <Type type="sister" />
+ <Type type="spouse" />
+ <Type type="custom" />
+ </DataKind>
+ </EditSchema>
+</ContactsAccountType>
diff --git a/tests/res/xml/test_basic_syncadapter.xml b/tests/res/xml/test_basic_syncadapter.xml
new file mode 100644
index 0000000..fecc0eb
--- /dev/null
+++ b/tests/res/xml/test_basic_syncadapter.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+ android:contentAuthority="com.android.contacts"
+ android:accountType="com.android.contacts.tests.authtest.basic"
+ android:supportsUploading="true"
+ android:userVisible="true"
+/>
diff --git a/tests/src/com/android/contacts/common/ContactsUtilsTests.java b/tests/src/com/android/contacts/common/ContactsUtilsTests.java
new file mode 100644
index 0000000..a209fb2
--- /dev/null
+++ b/tests/src/com/android/contacts/common/ContactsUtilsTests.java
@@ -0,0 +1,188 @@
+/*
+ * 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.common;
+
+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.SmallTest;
+import android.util.Pair;
+
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.model.dataitem.DataItem;
+import com.android.contacts.common.model.dataitem.EmailDataItem;
+import com.android.contacts.common.model.dataitem.ImDataItem;
+
+/**
+ * Tests for {@link ContactsUtils}.
+ */
+@SmallTest
+public class ContactsUtilsTests extends AndroidTestCase {
+
+ private static final String TEST_ADDRESS = "user@example.org";
+ private static final String TEST_PROTOCOL = "prot%col";
+
+ 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("."));
+ }
+
+ public void testAreObjectsEqual() throws Exception {
+ assertTrue("null:null", ContactsUtils.areObjectsEqual(null, null));
+ assertTrue("1:1", ContactsUtils.areObjectsEqual(1, 1));
+
+ assertFalse("null:1", ContactsUtils.areObjectsEqual(null, 1));
+ assertFalse("1:null", ContactsUtils.areObjectsEqual(1, null));
+ assertFalse("1:2", ContactsUtils.areObjectsEqual(1, 2));
+ }
+
+ public void testAreIntentActionEqual() throws Exception {
+ assertTrue("1", ContactsUtils.areIntentActionEqual(null, null));
+ assertTrue("1", ContactsUtils.areIntentActionEqual(new Intent("a"), new Intent("a")));
+
+ assertFalse("11", ContactsUtils.areIntentActionEqual(new Intent("a"), null));
+ assertFalse("12", ContactsUtils.areIntentActionEqual(null, new Intent("a")));
+
+ assertFalse("21", ContactsUtils.areIntentActionEqual(new Intent("a"), new Intent()));
+ assertFalse("22", ContactsUtils.areIntentActionEqual(new Intent(), new Intent("b")));
+ assertFalse("23", ContactsUtils.areIntentActionEqual(new Intent("a"), new Intent("b")));
+ }
+
+ public void testImIntentCustom() throws Exception {
+ // Custom IM types have encoded authority. We send the imto Intent here, because
+ // legacy third party apps might not accept xmpp yet
+ 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 ImDataItem im = (ImDataItem) DataItem.createFrom(values);
+
+ final Pair<Intent, Intent> intents = ContactsUtils.buildImIntent(getContext(), im);
+ final Intent imIntent = intents.first;
+
+ assertEquals(Intent.ACTION_SENDTO, imIntent.getAction());
+
+ final Uri data = imIntent.getData();
+ assertEquals("imto", data.getScheme());
+ assertEquals(TEST_PROTOCOL, data.getAuthority());
+ assertEquals(TEST_ADDRESS, data.getPathSegments().get(0));
+
+ assertNull(intents.second);
+ }
+
+ public void testImIntent() throws Exception {
+ // Test GTalk XMPP URI. No chat capabilities provided
+ 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 ImDataItem im = (ImDataItem) DataItem.createFrom(values);
+
+ final Pair<Intent, Intent> intents = ContactsUtils.buildImIntent(getContext(), im);
+ final Intent imIntent = intents.first;
+
+ assertEquals(Intent.ACTION_SENDTO, imIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?message", imIntent.getData().toString());
+
+ assertNull(intents.second);
+ }
+
+ public void testImIntentWithAudio() throws Exception {
+ // Test GTalk XMPP URI. Audio chat capabilities provided
+ 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);
+ values.put(Im.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO);
+ final ImDataItem im = (ImDataItem) DataItem.createFrom(values);
+
+ final Pair<Intent, Intent> intents = ContactsUtils.buildImIntent(getContext(), im);
+ final Intent imIntent = intents.first;
+
+ assertEquals(Intent.ACTION_SENDTO, imIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?message", imIntent.getData().toString());
+
+ final Intent secondaryIntent = intents.second;
+ assertEquals(Intent.ACTION_SENDTO, secondaryIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?call", secondaryIntent.getData().toString());
+ }
+
+ public void testImIntentWithVideo() throws Exception {
+ // Test GTalk XMPP URI. Video chat capabilities provided
+ 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);
+ values.put(Im.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO |
+ Im.CAPABILITY_HAS_VOICE);
+ final ImDataItem im = (ImDataItem) DataItem.createFrom(values);
+
+ final Pair<Intent, Intent> intents = ContactsUtils.buildImIntent(getContext(), im);
+ final Intent imIntent = intents.first;
+
+ assertEquals(Intent.ACTION_SENDTO, imIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?message", imIntent.getData().toString());
+
+ final Intent secondaryIntent = intents.second;
+ assertEquals(Intent.ACTION_SENDTO, secondaryIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?call", secondaryIntent.getData().toString());
+ }
+
+
+ public void testImEmailIntent() throws Exception {
+ // Email addresses are treated as Google Talk entries
+ // This test only tests the VIDEO+CAMERA case. The other cases have been addressed by the
+ // Im tests
+ 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);
+ values.put(Email.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO |
+ Im.CAPABILITY_HAS_VOICE);
+ final ImDataItem im = ImDataItem.createFromEmail(
+ (EmailDataItem) DataItem.createFrom(values));
+
+ final Pair<Intent, Intent> intents = ContactsUtils.buildImIntent(getContext(), im);
+ final Intent imIntent = intents.first;
+
+ assertEquals(Intent.ACTION_SENDTO, imIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?message", imIntent.getData().toString());
+
+ final Intent secondaryIntent = intents.second;
+ assertEquals(Intent.ACTION_SENDTO, secondaryIntent.getAction());
+ assertEquals("xmpp:" + TEST_ADDRESS + "?call", secondaryIntent.getData().toString());
+ }
+}
diff --git a/tests/src/com/android/contacts/common/MoreContactUtilsTest.java b/tests/src/com/android/contacts/common/MoreContactUtilsTest.java
new file mode 100644
index 0000000..8d74455
--- /dev/null
+++ b/tests/src/com/android/contacts/common/MoreContactUtilsTest.java
@@ -0,0 +1,176 @@
+package com.android.contacts.common;
+
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for MoreContactsUtils.
+ */
+@SmallTest
+public class MoreContactUtilsTest extends TestCase {
+
+ public void testShouldCollapse() throws Exception {
+ assertCollapses("1", true, null, null, null, null);
+ assertCollapses("2", true, "a", "b", "a", "b");
+
+ assertCollapses("11", false, "a", null, null, null);
+ assertCollapses("12", false, null, "a", null, null);
+ assertCollapses("13", false, null, null, "a", null);
+ assertCollapses("14", false, null, null, null, "a");
+
+ assertCollapses("21", false, "a", "b", null, null);
+ assertCollapses("22", false, "a", "b", "a", null);
+ assertCollapses("23", false, "a", "b", null, "b");
+ assertCollapses("24", false, "a", "b", "a", "x");
+ assertCollapses("25", false, "a", "b", "x", "b");
+
+ assertCollapses("31", false, null, null, "a", "b");
+ assertCollapses("32", false, "a", null, "a", "b");
+ assertCollapses("33", false, null, "b", "a", "b");
+ assertCollapses("34", false, "a", "x", "a", "b");
+ assertCollapses("35", false, "x", "b", "a", "b");
+
+ assertCollapses("41", true, Phone.CONTENT_ITEM_TYPE, null, Phone.CONTENT_ITEM_TYPE, null);
+ assertCollapses("42", true, Phone.CONTENT_ITEM_TYPE, "1", Phone.CONTENT_ITEM_TYPE, "1");
+
+ assertCollapses("51", false, Phone.CONTENT_ITEM_TYPE, "1", Phone.CONTENT_ITEM_TYPE, "2");
+ assertCollapses("52", false, Phone.CONTENT_ITEM_TYPE, "1", Phone.CONTENT_ITEM_TYPE, null);
+ assertCollapses("53", false, Phone.CONTENT_ITEM_TYPE, null, Phone.CONTENT_ITEM_TYPE, "2");
+
+ // Test phone numbers
+ assertCollapses("60", true, Phone.CONTENT_ITEM_TYPE, "1234567", Phone.CONTENT_ITEM_TYPE,
+ "1234567");
+ assertCollapses("61", false, Phone.CONTENT_ITEM_TYPE, "1234567", Phone.CONTENT_ITEM_TYPE,
+ "1234568");
+ assertCollapses("62", true, Phone.CONTENT_ITEM_TYPE, "1234567;0", Phone.CONTENT_ITEM_TYPE,
+ "1234567;0");
+ assertCollapses("63", false, Phone.CONTENT_ITEM_TYPE, "1234567;89321",
+ Phone.CONTENT_ITEM_TYPE, "1234567;89322");
+ assertCollapses("64", true, Phone.CONTENT_ITEM_TYPE, "1234567;89321",
+ Phone.CONTENT_ITEM_TYPE, "1234567;89321");
+ assertCollapses("65", false, Phone.CONTENT_ITEM_TYPE, "1234567;0111111111",
+ Phone.CONTENT_ITEM_TYPE, "1234567;");
+ assertCollapses("66", false, Phone.CONTENT_ITEM_TYPE, "12345675426;91970xxxxx",
+ Phone.CONTENT_ITEM_TYPE, "12345675426");
+ assertCollapses("67", false, Phone.CONTENT_ITEM_TYPE, "12345675426;23456xxxxx",
+ Phone.CONTENT_ITEM_TYPE, "12345675426;234567xxxx");
+ assertCollapses("68", true, Phone.CONTENT_ITEM_TYPE, "1234567;1234567;1234567",
+ Phone.CONTENT_ITEM_TYPE, "1234567;1234567;1234567");
+ assertCollapses("69", false, Phone.CONTENT_ITEM_TYPE, "1234567;1234567;1234567",
+ Phone.CONTENT_ITEM_TYPE, "1234567;1234567");
+
+ // test some numbers with country and area code
+ assertCollapses("70", true, Phone.CONTENT_ITEM_TYPE, "+49 (89) 12345678",
+ Phone.CONTENT_ITEM_TYPE, "+49 (89) 12345678");
+ assertCollapses("71", true, Phone.CONTENT_ITEM_TYPE, "+49 (89) 12345678",
+ Phone.CONTENT_ITEM_TYPE, "+49 (89)12345678");
+ assertCollapses("72", true, Phone.CONTENT_ITEM_TYPE, "+49 (8092) 1234",
+ Phone.CONTENT_ITEM_TYPE, "+49 (8092)1234");
+ assertCollapses("73", false, Phone.CONTENT_ITEM_TYPE, "0049 (8092) 1234",
+ Phone.CONTENT_ITEM_TYPE, "+49/80921234");
+ assertCollapses("74", false, Phone.CONTENT_ITEM_TYPE, "+49 (89) 12345678",
+ Phone.CONTENT_ITEM_TYPE, "+49 (89) 12345679");
+
+ // test special handling of collapsing country code for NANP region only
+ // This is non symmetrical, because we prefer the number with the +1.
+ assertEquals("100", true, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "+1 (415) 555-1212", Phone.CONTENT_ITEM_TYPE, "(415) 555-1212"));
+ assertEquals("101", true, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "+14155551212", Phone.CONTENT_ITEM_TYPE, "4155551212"));
+ assertEquals("102", false, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "(415) 555-1212", Phone.CONTENT_ITEM_TYPE, "+1 (415) 555-1212"));
+ assertEquals("103", false, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "4155551212", Phone.CONTENT_ITEM_TYPE, "+14155551212"));
+ // Require explicit +1 country code declaration to collapse
+ assertEquals("104", false, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "1-415-555-1212", Phone.CONTENT_ITEM_TYPE, "415-555-1212"));
+ assertEquals("105", false, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "14155551212", Phone.CONTENT_ITEM_TYPE, "4155551212"));
+ assertEquals("106", false, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "+1 (415) 555-1212", Phone.CONTENT_ITEM_TYPE, " 1 (415) 555-1212"));
+ assertEquals("107", false, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "+14155551212", Phone.CONTENT_ITEM_TYPE, " 14155551212"));
+ assertEquals("108", false, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "1 (415) 555-1212", Phone.CONTENT_ITEM_TYPE, "+1 (415) 555-1212"));
+ assertEquals("109", false, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "14155551212", Phone.CONTENT_ITEM_TYPE, "+14155551212"));
+
+ // test some numbers with wait symbol and area code
+ assertCollapses("200", true, Phone.CONTENT_ITEM_TYPE, "+49 (8092) 1234;89321",
+ Phone.CONTENT_ITEM_TYPE, "+49/80921234;89321");
+ assertCollapses("201", false, Phone.CONTENT_ITEM_TYPE, "+49 (8092) 1234;89321",
+ Phone.CONTENT_ITEM_TYPE, "+49/80921235;89321");
+ assertCollapses("202", false, Phone.CONTENT_ITEM_TYPE, "+49 (8092) 1234;89322",
+ Phone.CONTENT_ITEM_TYPE, "+49/80921234;89321");
+ assertCollapses("203", true, Phone.CONTENT_ITEM_TYPE, "1234567;+49 (8092) 1234",
+ Phone.CONTENT_ITEM_TYPE, "1234567;+49/80921234");
+
+ assertCollapses("300", true, Phone.CONTENT_ITEM_TYPE, "", Phone.CONTENT_ITEM_TYPE, "");
+
+ assertCollapses("301", false, Phone.CONTENT_ITEM_TYPE, "1", Phone.CONTENT_ITEM_TYPE, "");
+
+ assertCollapses("302", false, Phone.CONTENT_ITEM_TYPE, "", Phone.CONTENT_ITEM_TYPE, "1");
+
+ assertCollapses("303", true, Phone.CONTENT_ITEM_TYPE, "---", Phone.CONTENT_ITEM_TYPE, "---");
+
+ assertCollapses("304", false, Phone.CONTENT_ITEM_TYPE, "1-/().", Phone.CONTENT_ITEM_TYPE,
+ "--$%1");
+
+ // Test numbers using keypad letters. This is non-symmetrical, because we prefer
+ // the version with letters.
+ assertEquals("400", true, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "abcdefghijklmnopqrstuvwxyz", Phone.CONTENT_ITEM_TYPE,
+ "22233344455566677778889999"));
+ assertEquals("401", false, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "22233344455566677778889999", Phone.CONTENT_ITEM_TYPE,
+ "abcdefghijklmnopqrstuvwxyz"));
+
+ assertCollapses("402", false, Phone.CONTENT_ITEM_TYPE, "1;2", Phone.CONTENT_ITEM_TYPE,
+ "12");
+
+ assertCollapses("403", false, Phone.CONTENT_ITEM_TYPE, "1,2", Phone.CONTENT_ITEM_TYPE,
+ "12");
+ }
+
+ public void testShouldCollapse_collapsesSameNumberWithDifferentFormats() {
+ assertEquals("1", true, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "555-1212", Phone.CONTENT_ITEM_TYPE, "5551212"));
+ assertEquals("1", true, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "415-555-1212", Phone.CONTENT_ITEM_TYPE, "(415) 555-1212"));
+ assertEquals("2", true, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "4155551212", Phone.CONTENT_ITEM_TYPE, "(415) 555-1212"));
+ assertEquals("3", true, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "1-415-555-1212", Phone.CONTENT_ITEM_TYPE, "1 (415) 555-1212"));
+ assertEquals("4", true, MoreContactUtils.shouldCollapse(Phone.CONTENT_ITEM_TYPE,
+ "14155551212", Phone.CONTENT_ITEM_TYPE, "1 (415) 555-1212"));
+ }
+
+ private void assertCollapses(String message, boolean expected, CharSequence mimetype1,
+ CharSequence data1, CharSequence mimetype2, CharSequence data2) {
+ assertEquals(message, expected, MoreContactUtils.shouldCollapse(mimetype1, data1, mimetype2,
+ data2));
+ assertEquals(message, expected, MoreContactUtils.shouldCollapse(mimetype2, data2, mimetype1,
+ data1));
+
+ // If data1 and data2 are the same instance, make sure the same test passes with different
+ // instances.
+ if (data1 == data2 && data1 != null) {
+ // Create a different instance
+ final CharSequence data2_newref = new StringBuilder(data2).append("").toString();
+
+ if (data1 == data2_newref) {
+ // In some cases no matter what we do the runtime reuses the same instance, so
+ // we can't do the "different instance" test.
+ return;
+ }
+
+ // we have two different instances, now make sure we get the same result as before
+ assertEquals(message, expected, MoreContactUtils.shouldCollapse(mimetype1, data1,
+ mimetype2, data2_newref));
+ assertEquals(message, expected, MoreContactUtils.shouldCollapse(mimetype2, data2_newref,
+ mimetype1, data1));
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/common/RawContactDeltaListTests.java b/tests/src/com/android/contacts/common/RawContactDeltaListTests.java
new file mode 100644
index 0000000..77acb98
--- /dev/null
+++ b/tests/src/com/android/contacts/common/RawContactDeltaListTests.java
@@ -0,0 +1,608 @@
+/*
+ * 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.common;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.provider.ContactsContract.AggregationExceptions;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.contacts.common.RawContactModifierTests.MockContactsSource;
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.model.CPOWrapper;
+import com.android.contacts.common.model.RawContact;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.account.AccountType;
+import com.google.common.collect.Lists;
+
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Tests for {@link RawContactDeltaList} which focus on "diff" operations that should
+ * create {@link AggregationExceptions} in certain cases.
+ */
+@LargeTest
+public class RawContactDeltaListTests extends AndroidTestCase {
+ public static final String TAG = RawContactDeltaListTests.class.getSimpleName();
+
+ // From android.content.ContentProviderOperation
+ public static final int TYPE_INSERT = 1;
+ public static final int TYPE_UPDATE = 2;
+ public static final int TYPE_DELETE = 3;
+ public static final int TYPE_ASSERT = 4;
+
+ 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 RawContactDeltaListTests() {
+ super();
+ }
+
+ @Override
+ public void setUp() {
+ mContext = getContext();
+ }
+
+ /**
+ * Build a {@link AccountType} that has various odd constraints for
+ * testing purposes.
+ */
+ protected AccountType getAccountType() {
+ return new MockContactsSource();
+ }
+
+ static ContentValues getValues(ContentProviderOperation operation)
+ throws NoSuchFieldException, IllegalAccessException {
+ final Field field = ContentProviderOperation.class.getDeclaredField("mValues");
+ field.setAccessible(true);
+ return (ContentValues) field.get(operation);
+ }
+
+ static RawContactDelta getUpdate(Context context, long rawContactId) {
+ final RawContact before = RawContactDeltaTests.getRawContact(context, rawContactId,
+ RawContactDeltaTests.TEST_PHONE_ID);
+ return RawContactDelta.fromBefore(before);
+ }
+
+ static RawContactDelta getInsert() {
+ final ContentValues after = new ContentValues();
+ after.put(RawContacts.ACCOUNT_NAME, RawContactDeltaTests.TEST_ACCOUNT_NAME);
+ after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
+
+ final ValuesDelta values = ValuesDelta.fromAfter(after);
+ return new RawContactDelta(values);
+ }
+
+ static RawContactDeltaList buildSet(RawContactDelta... deltas) {
+ final RawContactDeltaList set = new RawContactDeltaList();
+ Collections.addAll(set, deltas);
+ return set;
+ }
+
+ static RawContactDelta buildBeforeEntity(Context context, 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 RawContact before = new RawContact(contact);
+ for (ContentValues entry : entries) {
+ before.addDataItemValues(entry);
+ }
+ return RawContactDelta.fromBefore(before);
+ }
+
+ static RawContactDelta buildAfterEntity(ContentValues... entries) {
+ // Build an existing contact read from database
+ final ContentValues contact = new ContentValues();
+ contact.put(RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT);
+ final RawContactDelta after = new RawContactDelta(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(RawContactDeltaList set, long rawContactId, ContentValues values) {
+ final RawContactDelta match = set.getByRawContactId(rawContactId);
+ match.addEntry(ValuesDelta.fromAfter(values));
+ }
+
+ static ValuesDelta getPhone(RawContactDeltaList set, long rawContactId, long dataId) {
+ final RawContactDelta match = set.getByRawContactId(rawContactId);
+ return match.getEntry(dataId);
+ }
+
+ static void assertDiffPattern(RawContactDelta delta, CPOWrapper... pattern) {
+ final ArrayList<CPOWrapper> diff = Lists.newArrayList();
+ delta.buildAssertWrapper(diff);
+ delta.buildDiffWrapper(diff);
+ assertDiffPattern(diff, pattern);
+ }
+
+ static void assertDiffPattern(RawContactDeltaList set, CPOWrapper... pattern) {
+ assertDiffPattern(set.buildDiffWrapper(), pattern);
+ }
+
+ static void assertDiffPattern(ArrayList<CPOWrapper> diff, CPOWrapper... pattern) {
+ assertEquals("Unexpected operations", pattern.length, diff.size());
+ for (int i = 0; i < pattern.length; i++) {
+ final CPOWrapper expected = pattern[i];
+ final CPOWrapper found = diff.get(i);
+
+ assertEquals("Unexpected uri",
+ expected.getOperation().getUri(), found.getOperation().getUri());
+
+ final String expectedType = getTypeString(expected);
+ final String foundType = getTypeString(found);
+ assertEquals("Unexpected type", expectedType, foundType);
+
+ if (CompatUtils.isDeleteCompat(expected)) continue;
+
+ try {
+ final ContentValues expectedValues = getValues(expected.getOperation());
+ final ContentValues foundValues = getValues(found.getOperation());
+
+ 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 getTypeString(CPOWrapper cpoWrapper) {
+ if (CompatUtils.isAssertQueryCompat(cpoWrapper)) {
+ return "TYPE_ASSERT";
+ } else if (CompatUtils.isInsertCompat(cpoWrapper)) {
+ return "TYPE_INSERT";
+ } else if (CompatUtils.isUpdateCompat(cpoWrapper)) {
+ return "TYPE_UPDATE";
+ } else if (CompatUtils.isDeleteCompat(cpoWrapper)) {
+ return "TYPE_DELETE";
+ }
+ return "TYPE_UNKNOWN";
+ }
+
+ static CPOWrapper buildAssertVersion(long version) {
+ final ContentValues values = new ContentValues();
+ values.put(RawContacts.VERSION, version);
+ return buildCPOWrapper(RawContacts.CONTENT_URI, TYPE_ASSERT, values);
+ }
+
+ static CPOWrapper buildAggregationModeUpdate(int mode) {
+ final ContentValues values = new ContentValues();
+ values.put(RawContacts.AGGREGATION_MODE, mode);
+ return buildCPOWrapper(RawContacts.CONTENT_URI, TYPE_UPDATE, values);
+ }
+
+ static CPOWrapper buildUpdateAggregationSuspended() {
+ return buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_SUSPENDED);
+ }
+
+ static CPOWrapper buildUpdateAggregationDefault() {
+ return buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT);
+ }
+
+ static CPOWrapper buildUpdateAggregationKeepTogether(long rawContactId) {
+ final ContentValues values = new ContentValues();
+ values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId);
+ values.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
+ return buildCPOWrapper(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 CPOWrapper buildDelete(Uri uri) {
+ return buildCPOWrapper(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 CPOWrapper buildCPOWrapper(Uri uri, int type, ContentValues values) {
+ if (type == TYPE_ASSERT || type == TYPE_INSERT || type == TYPE_UPDATE
+ || type == TYPE_DELETE) {
+ return new CPOWrapper(buildOper(uri, type, values), type);
+ }
+ return null;
+ }
+
+ static Long getVersion(RawContactDeltaList set, Long rawContactId) {
+ return set.getByRawContactId(rawContactId).getValues().getAsLong(RawContacts.VERSION);
+ }
+
+ /**
+ * Count number of {@link AggregationExceptions} updates contained in the
+ * given list of {@link CPOWrapper}.
+ */
+ static int countExceptionUpdates(ArrayList<CPOWrapper> diff) {
+ int updateCount = 0;
+ for (CPOWrapper cpoWrapper : diff) {
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ if (AggregationExceptions.CONTENT_URI.equals(oper.getUri())
+ && CompatUtils.isUpdateCompat(cpoWrapper)) {
+ updateCount++;
+ }
+ }
+ return updateCount;
+ }
+
+ public void testInsert() {
+ final RawContactDelta insert = getInsert();
+ final RawContactDeltaList set = buildSet(insert);
+
+ // Inserting single shouldn't create rules
+ final ArrayList<CPOWrapper> diff = set.buildDiffWrapper();
+ final int exceptionCount = countExceptionUpdates(diff);
+ assertEquals("Unexpected exception updates", 0, exceptionCount);
+ }
+
+ public void testUpdateUpdate() {
+ final RawContactDelta updateFirst = getUpdate(mContext, CONTACT_FIRST);
+ final RawContactDelta updateSecond = getUpdate(mContext, CONTACT_SECOND);
+ final RawContactDeltaList set = buildSet(updateFirst, updateSecond);
+
+ // Updating two existing shouldn't create rules
+ final ArrayList<CPOWrapper> diff = set.buildDiffWrapper();
+ final int exceptionCount = countExceptionUpdates(diff);
+ assertEquals("Unexpected exception updates", 0, exceptionCount);
+ }
+
+ public void testUpdateInsert() {
+ final RawContactDelta update = getUpdate(mContext, CONTACT_FIRST);
+ final RawContactDelta insert = getInsert();
+ final RawContactDeltaList set = buildSet(update, insert);
+
+ // New insert should only create one rule
+ final ArrayList<CPOWrapper> diff = set.buildDiffWrapper();
+ final int exceptionCount = countExceptionUpdates(diff);
+ assertEquals("Unexpected exception updates", 1, exceptionCount);
+ }
+
+ public void testInsertUpdateInsert() {
+ final RawContactDelta insertFirst = getInsert();
+ final RawContactDelta update = getUpdate(mContext, CONTACT_FIRST);
+ final RawContactDelta insertSecond = getInsert();
+ final RawContactDeltaList set = buildSet(insertFirst, update, insertSecond);
+
+ // Two inserts should create two rules to bind against single existing
+ final ArrayList<CPOWrapper> diff = set.buildDiffWrapper();
+ final int exceptionCount = countExceptionUpdates(diff);
+ assertEquals("Unexpected exception updates", 2, exceptionCount);
+ }
+
+ public void testInsertInsertInsert() {
+ final RawContactDelta insertFirst = getInsert();
+ final RawContactDelta insertSecond = getInsert();
+ final RawContactDelta insertThird = getInsert();
+ final RawContactDeltaList set = buildSet(insertFirst, insertSecond, insertThird);
+
+ // Three new inserts should create only two binding rules
+ final ArrayList<CPOWrapper> diff = set.buildDiffWrapper();
+ final int exceptionCount = countExceptionUpdates(diff);
+ assertEquals("Unexpected exception updates", 2, exceptionCount);
+ }
+
+ public void testMergeDataRemoteInsert() {
+ final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_FIRST, buildPhone(PHONE_RED)));
+ final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_SECOND, buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
+
+ // Merge in second version, verify they match
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
+ assertEquals("Unexpected change when merging", second, merged);
+ }
+
+ public void testMergeDataLocalUpdateRemoteInsert() {
+ final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_FIRST, buildPhone(PHONE_RED)));
+ final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, 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(),
+ buildCPOWrapper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
+ buildUpdateAggregationDefault());
+
+ // Merge in the second version, verify diff matches
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildUpdateAggregationSuspended(),
+ buildCPOWrapper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
+ buildUpdateAggregationDefault());
+ }
+
+ public void testMergeDataLocalUpdateRemoteDelete() {
+ final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_FIRST, buildPhone(PHONE_RED)));
+ final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, 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(),
+ buildCPOWrapper(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 RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildUpdateAggregationSuspended(),
+ buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(phone, CONTACT_BOB)),
+ buildUpdateAggregationDefault());
+ }
+
+ public void testMergeDataLocalDeleteRemoteUpdate() {
+ final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_FIRST, buildPhone(PHONE_RED)));
+ final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, 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 RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildUpdateAggregationSuspended(),
+ buildDelete(Data.CONTENT_URI),
+ buildUpdateAggregationDefault());
+ }
+
+ public void testMergeDataLocalInsertRemoteInsert() {
+ final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_FIRST, buildPhone(PHONE_RED)));
+ final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, 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(),
+ buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bluePhone, CONTACT_BOB)),
+ buildUpdateAggregationDefault());
+
+ // Merge in the second version, verify that our insert remains
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildUpdateAggregationSuspended(),
+ buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bluePhone, CONTACT_BOB)),
+ buildUpdateAggregationDefault());
+ }
+
+ public void testMergeRawContactLocalInsertRemoteInsert() {
+ final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_FIRST, buildPhone(PHONE_RED)));
+ final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_SECOND, buildPhone(PHONE_RED)), buildBeforeEntity(mContext, CONTACT_MARY,
+ VER_SECOND, buildPhone(PHONE_RED)));
+
+ // Add new contact locally, should remain insert
+ final ContentValues joePhoneInsert = buildPhone(PHONE_BLUE);
+ final RawContactDelta joeContact = buildAfterEntity(joePhoneInsert);
+ final ContentValues joeContactInsert = joeContact.getValues().getCompleteValues();
+ joeContactInsert.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
+ first.add(joeContact);
+ assertDiffPattern(first,
+ buildAssertVersion(VER_FIRST),
+ buildCPOWrapper(RawContacts.CONTENT_URI, TYPE_INSERT, joeContactInsert),
+ buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, joePhoneInsert),
+ buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
+ buildUpdateAggregationKeepTogether(CONTACT_BOB));
+
+ // Merge in the second version, verify that our insert remains
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildAssertVersion(VER_SECOND),
+ buildCPOWrapper(RawContacts.CONTENT_URI, TYPE_INSERT, joeContactInsert),
+ buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, joePhoneInsert),
+ buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
+ buildUpdateAggregationKeepTogether(CONTACT_BOB));
+ }
+
+ public void testMergeRawContactLocalDeleteRemoteDelete() {
+ final RawContactDeltaList first = buildSet(
+ buildBeforeEntity(mContext, CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
+ buildBeforeEntity(mContext, CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
+ final RawContactDeltaList second = buildSet(
+ buildBeforeEntity(mContext, 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 RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
+ assertDiffPattern(merged);
+ }
+
+ public void testMergeRawContactLocalUpdateRemoteDelete() {
+ final RawContactDeltaList first = buildSet(
+ buildBeforeEntity(mContext, CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
+ buildBeforeEntity(mContext, CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
+ final RawContactDeltaList second = buildSet(
+ buildBeforeEntity(mContext, 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(),
+ buildCPOWrapper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
+ buildUpdateAggregationDefault());
+
+ final ContentValues phoneInsert = phone.getCompleteValues();
+ final ContentValues contactInsert = first.getByRawContactId(CONTACT_MARY).getValues()
+ .getCompleteValues();
+ contactInsert.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
+
+ // Merge and verify that update turned into insert
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
+ assertDiffPattern(merged,
+ buildAssertVersion(VER_SECOND),
+ buildCPOWrapper(RawContacts.CONTENT_URI, TYPE_INSERT, contactInsert),
+ buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, phoneInsert),
+ buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
+ buildUpdateAggregationKeepTogether(CONTACT_BOB));
+ }
+
+ public void testMergeUsesNewVersion() {
+ final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_FIRST, buildPhone(PHONE_RED)));
+ final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_SECOND, buildPhone(PHONE_RED)));
+
+ assertEquals((Long)VER_FIRST, getVersion(first, CONTACT_BOB));
+ assertEquals((Long)VER_SECOND, getVersion(second, CONTACT_BOB));
+
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
+ assertEquals((Long)VER_SECOND, getVersion(merged, CONTACT_BOB));
+ }
+
+ public void testMergeAfterEnsureAndTrim() {
+ final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_FIRST, buildEmail(EMAIL_YELLOW)));
+ final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
+ VER_SECOND, buildEmail(EMAIL_YELLOW)));
+
+ // Ensure we have at least one phone
+ final AccountType source = getAccountType();
+ final RawContactDelta bobContact = first.getByRawContactId(CONTACT_BOB);
+ RawContactModifier.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(),
+ buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bobPhone, CONTACT_BOB)),
+ buildUpdateAggregationDefault());
+
+ // Trim values and ensure that we don't insert things
+ RawContactModifier.trimEmpty(bobContact, source);
+ assertDiffPattern(first);
+
+ // Now re-parent the change, which should remain no-op
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
+ assertDiffPattern(merged);
+ }
+}
diff --git a/tests/src/com/android/contacts/common/RawContactDeltaTests.java b/tests/src/com/android/contacts/common/RawContactDeltaTests.java
new file mode 100644
index 0000000..e4690d9
--- /dev/null
+++ b/tests/src/com/android/contacts/common/RawContactDeltaTests.java
@@ -0,0 +1,383 @@
+/*
+ * 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.common;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.content.Context;
+import android.os.Build;
+import android.os.Parcel;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.model.BuilderWrapper;
+import com.android.contacts.common.model.CPOWrapper;
+import com.android.contacts.common.model.RawContact;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.ValuesDelta;
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for {@link RawContactDelta} and {@link ValuesDelta}. These tests
+ * focus on passing changes across {@link Parcel}, and verifying that they
+ * correctly build expected "diff" operations.
+ */
+@LargeTest
+public class RawContactDeltaTests 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 RawContactDeltaTests() {
+ super();
+ }
+
+ @Override
+ public void setUp() {
+ mContext = getContext();
+ }
+
+ public static RawContact getRawContact(Context context, 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 RawContact before = new RawContact(contact);
+ before.addDataItemValues(phone);
+ return before;
+ }
+
+ /**
+ * Test that {@link RawContactDelta#mergeAfter(RawContactDelta)} correctly passes
+ * any changes through the {@link Parcel} object. This enforces that
+ * {@link RawContactDelta} should be identical when serialized against the same
+ * "before" {@link RawContact}.
+ */
+ public void testParcelChangesNone() {
+ final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
+ final RawContactDelta source = RawContactDelta.fromBefore(before);
+ final RawContactDelta dest = RawContactDelta.fromBefore(before);
+
+ // Merge modified values and assert they match
+ final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
+ assertEquals("Unexpected change when merging", source, merged);
+ }
+
+ public void testParcelChangesInsert() {
+ final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
+ final RawContactDelta source = RawContactDelta.fromBefore(before);
+ final RawContactDelta dest = RawContactDelta.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 RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
+ assertEquals("Unexpected change when merging", source, merged);
+ }
+
+ public void testParcelChangesUpdate() {
+ // Update existing row and pass across parcel, should be same
+ final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
+ final RawContactDelta source = RawContactDelta.fromBefore(before);
+ final RawContactDelta dest = RawContactDelta.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 RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
+ assertEquals("Unexpected change when merging", source, merged);
+ }
+
+ public void testParcelChangesDelete() {
+ // Delete a row and pass across parcel, should be same
+ final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
+ final RawContactDelta source = RawContactDelta.fromBefore(before);
+ final RawContactDelta dest = RawContactDelta.fromBefore(before);
+
+ final ValuesDelta child = source.getEntry(TEST_PHONE_ID);
+ child.markDeleted();
+
+ // Merge modified values and assert they match
+ final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
+ assertEquals("Unexpected change when merging", source, merged);
+ }
+
+ 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 BuilderWrapper builderWrapper = values.buildDiffWrapper(Data.CONTENT_URI);
+ final boolean isDelete = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ ? builderWrapper.getBuilder().build().isDelete()
+ : builderWrapper.getType() == CompatUtils.TYPE_DELETE;
+ assertTrue("Didn't produce delete action", isDelete);
+ }
+
+ /**
+ * Test that {@link RawContactDelta#buildDiffWrapper(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 RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
+ final RawContactDelta source = RawContactDelta.fromBefore(before);
+
+ // Assert that writing unchanged produces few operations
+ final ArrayList<CPOWrapper> diff = Lists.newArrayList();
+ source.buildDiffWrapper(diff);
+
+ assertTrue("Created changes when none needed", (diff.size() == 0));
+ }
+
+ public void testEntityDiffNoneInsert() {
+ final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
+ final RawContactDelta source = RawContactDelta.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<CPOWrapper> diff = Lists.newArrayList();
+ source.buildAssertWrapper(diff);
+ source.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 4, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ assertTrue("Expected version enforcement", CompatUtils.isAssertQueryCompat(cpoWrapper));
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(2);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(3);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testEntityDiffUpdateInsert() {
+ final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
+ final RawContactDelta source = RawContactDelta.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<CPOWrapper> diff = Lists.newArrayList();
+ source.buildAssertWrapper(diff);
+ source.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 5, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ assertTrue("Expected version enforcement", CompatUtils.isAssertQueryCompat(cpoWrapper));
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(2);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(3);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(4);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testEntityDiffNoneUpdate() {
+ final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
+ final RawContactDelta source = RawContactDelta.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<CPOWrapper> diff = Lists.newArrayList();
+ source.buildAssertWrapper(diff);
+ source.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 4, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ assertTrue("Expected version enforcement", CompatUtils.isAssertQueryCompat(cpoWrapper));
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(2);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(3);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testEntityDiffDelete() {
+ final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
+ final RawContactDelta source = RawContactDelta.fromBefore(before);
+
+ // Delete entire entity
+ source.getValues().markDeleted();
+
+ // Assert two operations: delete Contact and enforce version
+ final ArrayList<CPOWrapper> diff = Lists.newArrayList();
+ source.buildAssertWrapper(diff);
+ source.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 2, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ assertTrue("Expected version enforcement", CompatUtils.isAssertQueryCompat(cpoWrapper));
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isDeleteCompat(cpoWrapper));
+ 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 RawContactDelta source = new RawContactDelta(values);
+
+ // Assert two operations: insert Contact and enforce version
+ final ArrayList<CPOWrapper> diff = Lists.newArrayList();
+ source.buildAssertWrapper(diff);
+ source.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 2, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
+ 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 RawContactDelta source = new RawContactDelta(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<CPOWrapper> diff = Lists.newArrayList();
+ source.buildAssertWrapper(diff);
+ source.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/common/RawContactModifierTests.java b/tests/src/com/android/contacts/common/RawContactModifierTests.java
new file mode 100644
index 0000000..755838b
--- /dev/null
+++ b/tests/src/com/android/contacts/common/RawContactModifierTests.java
@@ -0,0 +1,1293 @@
+/*
+ * 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.common;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents.Insert;
+import android.provider.ContactsContract.RawContacts;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.CPOWrapper;
+import com.android.contacts.common.model.RawContact;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountType.EditType;
+import com.android.contacts.common.model.account.ExchangeAccountType;
+import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.test.mocks.ContactsMockContext;
+import com.android.contacts.common.test.mocks.MockAccountTypeManager;
+import com.android.contacts.common.test.mocks.MockContentProvider;
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link RawContactModifier} to verify that {@link AccountType}
+ * constraints are being enforced correctly.
+ */
+@LargeTest
+public class RawContactModifierTests extends AndroidTestCase {
+ public static final String TAG = "EntityModifierTests";
+
+ // From android.content.ContentProviderOperation
+ public static final int TYPE_INSERT = 1;
+
+ 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_NAME = "Adam Young";
+ private static final String TEST_NAME2 = "Breanne Duren";
+ private static final String TEST_IM = "example@example.com";
+ private static final String TEST_POSTAL = "1600 Amphitheatre Parkway";
+
+ private static final String TEST_ACCOUNT_NAME = "unittest@example.com";
+ private static final String TEST_ACCOUNT_TYPE = "com.example.unittest";
+
+ private static final String EXCHANGE_ACCT_TYPE = "com.android.exchange";
+
+ @Override
+ public void setUp() {
+ mContext = getContext();
+ }
+
+ public static class MockContactsSource extends AccountType {
+
+ MockContactsSource() {
+ try {
+ this.accountType = TEST_ACCOUNT_TYPE;
+
+ final DataKind nameKind = new DataKind(StructuredName.CONTENT_ITEM_TYPE,
+ R.string.nameLabelsGroup, -1, true);
+ nameKind.typeOverallMax = 1;
+ addKind(nameKind);
+
+ // Phone allows maximum 2 home, 1 work, and unlimited other, with
+ // constraint of 5 numbers maximum.
+ final DataKind phoneKind = new DataKind(
+ Phone.CONTENT_ITEM_TYPE, -1, 10, true);
+
+ phoneKind.typeOverallMax = 5;
+ phoneKind.typeColumn = Phone.TYPE;
+ phoneKind.typeList = Lists.newArrayList();
+ phoneKind.typeList.add(new EditType(Phone.TYPE_HOME, -1).setSpecificMax(2));
+ phoneKind.typeList.add(new EditType(Phone.TYPE_WORK, -1).setSpecificMax(1));
+ phoneKind.typeList.add(new EditType(Phone.TYPE_FAX_WORK, -1).setSecondary(true));
+ phoneKind.typeList.add(new EditType(Phone.TYPE_OTHER, -1));
+
+ phoneKind.fieldList = Lists.newArrayList();
+ phoneKind.fieldList.add(new EditField(Phone.NUMBER, -1, -1));
+ phoneKind.fieldList.add(new EditField(Phone.LABEL, -1, -1));
+
+ addKind(phoneKind);
+
+ // Email is unlimited
+ final DataKind emailKind = new DataKind(Email.CONTENT_ITEM_TYPE, -1, 10, true);
+ emailKind.typeOverallMax = -1;
+ emailKind.fieldList = Lists.newArrayList();
+ emailKind.fieldList.add(new EditField(Email.DATA, -1, -1));
+ addKind(emailKind);
+
+ // IM is only one
+ final DataKind imKind = new DataKind(Im.CONTENT_ITEM_TYPE, -1, 10, true);
+ imKind.typeOverallMax = 1;
+ imKind.fieldList = Lists.newArrayList();
+ imKind.fieldList.add(new EditField(Im.DATA, -1, -1));
+ addKind(imKind);
+
+ // Organization is only one
+ final DataKind orgKind = new DataKind(Organization.CONTENT_ITEM_TYPE, -1, 10, true);
+ orgKind.typeOverallMax = 1;
+ orgKind.fieldList = Lists.newArrayList();
+ orgKind.fieldList.add(new EditField(Organization.COMPANY, -1, -1));
+ orgKind.fieldList.add(new EditField(Organization.TITLE, -1, -1));
+ addKind(orgKind);
+ } catch (DefinitionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return false;
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return true;
+ }
+ }
+
+ /**
+ * Build a {@link AccountType} that has various odd constraints for
+ * testing purposes.
+ */
+ protected AccountType getAccountType() {
+ return new MockContactsSource();
+ }
+
+ /**
+ * Build {@link AccountTypeManager} instance.
+ */
+ protected AccountTypeManager getAccountTypes(AccountType... types) {
+ return new MockAccountTypeManager(types, null);
+ }
+
+ /**
+ * Build an {@link RawContact} with the requested set of phone numbers.
+ */
+ protected RawContactDelta getRawContact(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 RawContact before = new RawContact(contact);
+ for (ContentValues values : entries) {
+ before.addDataItemValues(values);
+ }
+ return RawContactDelta.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 RawContactModifier#getValidTypes(RawContactDelta, DataKind, EditType)}
+ */
+ public void testValidTypes() {
+ // Build a source and pull specific types
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
+ final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+ List<EditType> validTypes;
+
+ // Add first home, first work
+ final RawContactDelta state = getRawContact(TEST_ID);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeWork);
+
+ // Expecting home, other
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null, true, null, true);
+ assertContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertContains(validTypes, typeOther);
+
+ // Add second home
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+
+ // Expecting other
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null, true, null, true);
+ assertNotContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertContains(validTypes, typeOther);
+
+ // Add third and fourth home (invalid, but possible)
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+
+ // Expecting none
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null, true, null, true);
+ assertNotContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertNotContains(validTypes, typeOther);
+ }
+
+ /**
+ * Test which valid types there are when trying to update the editor type.
+ * {@link RawContactModifier#getValidTypes(RawContactDelta, DataKind, EditType, Boolean)}
+ */
+ public void testValidTypesWhenUpdating() {
+ // Build a source and pull specific types
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
+ final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+ List<EditType> validTypes;
+
+ // Add first home, first work
+ final RawContactDelta state = getRawContact(TEST_ID);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeWork);
+
+ // Update editor type for home.
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null, true, null, false);
+ assertContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertContains(validTypes, typeOther);
+
+ // Add another 3 types. Overall limit is 5.
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeOther);
+ RawContactModifier.insertChild(state, kindPhone, typeOther);
+
+ // "Other" is valid when updating the editor type.
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null, true, null, false);
+ assertNotContains(validTypes, typeHome);
+ assertNotContains(validTypes, typeWork);
+ assertContains(validTypes, typeOther);
+ }
+
+ /**
+ * Test {@link RawContactModifier#canInsert(RawContactDelta, DataKind)} by
+ * inserting various rows.
+ */
+ public void testCanInsert() {
+ // Build a source and pull specific types
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
+ final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+ // Add first home, first work
+ final RawContactDelta state = getRawContact(TEST_ID);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeWork);
+ assertTrue("Unable to insert", RawContactModifier.canInsert(state, kindPhone));
+
+ // Add two other, which puts us just under "5" overall limit
+ RawContactModifier.insertChild(state, kindPhone, typeOther);
+ RawContactModifier.insertChild(state, kindPhone, typeOther);
+ assertTrue("Unable to insert", RawContactModifier.canInsert(state, kindPhone));
+
+ // Add second home, which should push to snug limit
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ assertFalse("Able to insert", RawContactModifier.canInsert(state, kindPhone));
+ }
+
+ /**
+ * Test
+ * {@link RawContactModifier#getBestValidType(RawContactDelta, DataKind, boolean, int)}
+ * by asserting expected best options in various states.
+ */
+ public void testBestValidType() {
+ // Build a source and pull specific types
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
+ final EditType typeFaxWork = RawContactModifier.getType(kindPhone, Phone.TYPE_FAX_WORK);
+ final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+ EditType suggested;
+
+ // Default suggestion should be home
+ final RawContactDelta state = getRawContact(TEST_ID);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeHome, suggested);
+
+ // Add first home, should now suggest work
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeWork, suggested);
+
+ // Add work fax, should still suggest work
+ RawContactModifier.insertChild(state, kindPhone, typeFaxWork);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeWork, suggested);
+
+ // Add other, should still suggest work
+ RawContactModifier.insertChild(state, kindPhone, typeOther);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeWork, suggested);
+
+ // Add work, now should suggest other
+ RawContactModifier.insertChild(state, kindPhone, typeWork);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ assertEquals("Unexpected suggestion", typeOther, suggested);
+ }
+
+ public void testIsEmptyEmpty() {
+ final AccountType source = getAccountType();
+ 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", RawContactModifier.isEmpty(values, kindPhone));
+ }
+
+ public void testIsEmptyDirectFields() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values, but core fields are empty
+ final RawContactDelta state = getRawContact(TEST_ID);
+ final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
+
+ assertTrue("Expected empty", RawContactModifier.isEmpty(values, kindPhone));
+
+ // Insert some data to trigger non-empty state
+ values.put(Phone.NUMBER, TEST_PHONE);
+
+ assertFalse("Expected non-empty", RawContactModifier.isEmpty(values, kindPhone));
+ }
+
+ public void testTrimEmptySingle() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values, but core fields are empty
+ final RawContactDelta state = getRawContact(TEST_ID);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+
+ // Build diff, expecting insert for data row and update enforcement
+ final ArrayList<CPOWrapper> diff = Lists.newArrayList();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(2);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Trim empty rows and try again, expecting delete of overall contact
+ RawContactModifier.trimEmpty(state, source);
+ diff.clear();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isDeleteCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testTrimEmptySpaces() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values, but values are spaces
+ final RawContactDelta state = RawContactDeltaListTests.buildBeforeEntity(mContext, TEST_ID,
+ VER_FIRST);
+ final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
+ values.put(Phone.NUMBER, " ");
+
+ // Build diff, expecting insert for data row and update enforcement
+ RawContactDeltaListTests.assertDiffPattern(state,
+ RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
+ RawContactDeltaListTests.buildUpdateAggregationSuspended(),
+ RawContactDeltaListTests.buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT,
+ RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
+ RawContactDeltaListTests.buildUpdateAggregationDefault());
+
+ // Trim empty rows and try again, expecting delete of overall contact
+ RawContactModifier.trimEmpty(state, source);
+ RawContactDeltaListTests.assertDiffPattern(state,
+ RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
+ RawContactDeltaListTests.buildDelete(RawContacts.CONTENT_URI));
+ }
+
+ public void testTrimLeaveValid() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Test row that has type values with valid number
+ final RawContactDelta state = RawContactDeltaListTests.buildBeforeEntity(mContext, TEST_ID,
+ VER_FIRST);
+ final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
+ values.put(Phone.NUMBER, TEST_PHONE);
+
+ // Build diff, expecting insert for data row and update enforcement
+ RawContactDeltaListTests.assertDiffPattern(state,
+ RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
+ RawContactDeltaListTests.buildUpdateAggregationSuspended(),
+ RawContactDeltaListTests.buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT,
+ RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
+ RawContactDeltaListTests.buildUpdateAggregationDefault());
+
+ // Trim empty rows and try again, expecting no differences
+ RawContactModifier.trimEmpty(state, source);
+ RawContactDeltaListTests.assertDiffPattern(state,
+ RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
+ RawContactDeltaListTests.buildUpdateAggregationSuspended(),
+ RawContactDeltaListTests.buildCPOWrapper(Data.CONTENT_URI, TYPE_INSERT,
+ RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
+ RawContactDeltaListTests.buildUpdateAggregationDefault());
+ }
+
+ public void testTrimEmptyUntouched() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Build "before" that has empty row
+ final RawContactDelta state = getRawContact(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<CPOWrapper> diff = Lists.newArrayList();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+
+ // Try trimming existing empty, which we shouldn't touch
+ RawContactModifier.trimEmpty(state, source);
+ diff.clear();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+ }
+
+ public void testTrimEmptyAfterUpdate() {
+ final AccountType source = getAccountType();
+ final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.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 RawContactDelta state = getRawContact(TEST_ID, before);
+
+ // Build diff, expecting no changes
+ final ArrayList<CPOWrapper> diff = Lists.newArrayList();
+ state.buildDiffWrapper(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.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(2);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Now run trim, which should turn that update into delete
+ RawContactModifier.trimEmpty(state, source);
+ diff.clear();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isDeleteCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testTrimInsertEmpty() {
+ final AccountType accountType = getAccountType();
+ final AccountTypeManager accountTypes = getAccountTypes(accountType);
+ final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Try creating a contact without any child entries
+ final RawContactDelta state = getRawContact(null);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
+
+ // Build diff, expecting single insert
+ final ArrayList<CPOWrapper> diff = Lists.newArrayList();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 2, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Trim empty rows and try again, expecting no insert
+ RawContactModifier.trimEmpty(set, accountTypes);
+ diff.clear();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+ }
+
+ public void testTrimInsertInsert() {
+ final AccountType accountType = getAccountType();
+ final AccountTypeManager accountTypes = getAccountTypes(accountType);
+ final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+
+ // Try creating a contact with single empty entry
+ final RawContactDelta state = getRawContact(null);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
+
+ // Build diff, expecting two insert operations
+ final ArrayList<CPOWrapper> diff = Lists.newArrayList();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isInsertCompat(cpoWrapper));
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+
+ // Trim empty rows and try again, expecting silence
+ RawContactModifier.trimEmpty(set, accountTypes);
+ diff.clear();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 0, diff.size());
+ }
+
+ public void testTrimUpdateRemain() {
+ final AccountType accountType = getAccountType();
+ final AccountTypeManager accountTypes = getAccountTypes(accountType);
+ final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.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 RawContactDelta state = getRawContact(TEST_ID, first, second);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
+
+ // Build diff, expecting no changes
+ final ArrayList<CPOWrapper> diff = Lists.newArrayList();
+ state.buildDiffWrapper(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.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(2);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Now run trim, which should turn that update into delete
+ RawContactModifier.trimEmpty(set, accountTypes);
+ diff.clear();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isDeleteCompat(cpoWrapper));
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(2);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testTrimUpdateUpdate() {
+ final AccountType accountType = getAccountType();
+ final AccountTypeManager accountTypes = getAccountTypes(accountType);
+ final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final EditType typeHome = RawContactModifier.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 RawContactDelta state = getRawContact(TEST_ID, first);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
+
+ // Build diff, expecting no changes
+ final ArrayList<CPOWrapper> diff = Lists.newArrayList();
+ state.buildDiffWrapper(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.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 3, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(1);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
+ }
+ {
+ final CPOWrapper cpoWrapper = diff.get(2);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Expected aggregation mode change", CompatUtils.isUpdateCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+
+ // Now run trim, which should turn into deleting the whole contact
+ RawContactModifier.trimEmpty(set, accountTypes);
+ diff.clear();
+ state.buildDiffWrapper(diff);
+ assertEquals("Unexpected operations", 1, diff.size());
+ {
+ final CPOWrapper cpoWrapper = diff.get(0);
+ final ContentProviderOperation oper = cpoWrapper.getOperation();
+ assertTrue("Incorrect type", CompatUtils.isDeleteCompat(cpoWrapper));
+ assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
+ }
+ }
+
+ public void testParseExtrasExistingName() {
+ final AccountType accountType = getAccountType();
+
+ // Build "before" name
+ final ContentValues first = new ContentValues();
+ first.put(Data._ID, TEST_ID);
+ first.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ first.put(StructuredName.GIVEN_NAME, TEST_NAME);
+
+ // Parse extras, making sure we keep single name
+ final RawContactDelta state = getRawContact(TEST_ID, first);
+ final Bundle extras = new Bundle();
+ extras.putString(Insert.NAME, TEST_NAME2);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
+
+ final int nameCount = state.getMimeEntriesCount(StructuredName.CONTENT_ITEM_TYPE, true);
+ assertEquals("Unexpected names", 1, nameCount);
+ }
+
+ public void testParseExtrasIgnoreLimit() {
+ final AccountType accountType = getAccountType();
+
+ // Build "before" IM
+ final ContentValues first = new ContentValues();
+ first.put(Data._ID, TEST_ID);
+ first.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ first.put(Im.DATA, TEST_IM);
+
+ final RawContactDelta state = getRawContact(TEST_ID, first);
+ final int beforeCount = state.getMimeEntries(Im.CONTENT_ITEM_TYPE).size();
+
+ // We should ignore data that doesn't fit account type rules, since account type
+ // only allows single Im
+ final Bundle extras = new Bundle();
+ extras.putInt(Insert.IM_PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
+ extras.putString(Insert.IM_HANDLE, TEST_IM);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
+
+ final int afterCount = state.getMimeEntries(Im.CONTENT_ITEM_TYPE).size();
+ assertEquals("Broke account type rules", beforeCount, afterCount);
+ }
+
+ public void testParseExtrasIgnoreUnhandled() {
+ final AccountType accountType = getAccountType();
+ final RawContactDelta state = getRawContact(TEST_ID);
+
+ // We should silently ignore types unsupported by account type
+ final Bundle extras = new Bundle();
+ extras.putString(Insert.POSTAL, TEST_POSTAL);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
+
+ assertNull("Broke accoun type rules",
+ state.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE));
+ }
+
+ public void testParseExtrasJobTitle() {
+ final AccountType accountType = getAccountType();
+ final RawContactDelta state = getRawContact(TEST_ID);
+
+ // Make sure that we create partial Organizations
+ final Bundle extras = new Bundle();
+ extras.putString(Insert.JOB_TITLE, TEST_NAME);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
+
+ final int count = state.getMimeEntries(Organization.CONTENT_ITEM_TYPE).size();
+ assertEquals("Expected to create organization", 1, count);
+ }
+
+ public void testMigrateWithDisplayNameFromGoogleToExchange1() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
+
+ ContactsMockContext context = new ContactsMockContext(getContext());
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredName.PREFIX, "prefix");
+ mockNameValues.put(StructuredName.GIVEN_NAME, "given");
+ mockNameValues.put(StructuredName.MIDDLE_NAME, "middle");
+ mockNameValues.put(StructuredName.FAMILY_NAME, "family");
+ mockNameValues.put(StructuredName.SUFFIX, "suffix");
+ mockNameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "PHONETIC_FAMILY");
+ mockNameValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "PHONETIC_MIDDLE");
+ mockNameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "PHONETIC_GIVEN");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
+ List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
+ assertEquals(1, list.size());
+
+ ContentValues output = list.get(0).getAfter();
+ assertEquals("prefix", output.getAsString(StructuredName.PREFIX));
+ assertEquals("given", output.getAsString(StructuredName.GIVEN_NAME));
+ assertEquals("middle", output.getAsString(StructuredName.MIDDLE_NAME));
+ assertEquals("family", output.getAsString(StructuredName.FAMILY_NAME));
+ assertEquals("suffix", output.getAsString(StructuredName.SUFFIX));
+ // Phonetic middle name isn't supported by Exchange.
+ assertEquals("PHONETIC_FAMILY", output.getAsString(StructuredName.PHONETIC_FAMILY_NAME));
+ assertEquals("PHONETIC_GIVEN", output.getAsString(StructuredName.PHONETIC_GIVEN_NAME));
+ }
+
+ public void testMigrateWithDisplayNameFromGoogleToExchange2() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
+
+ ContactsMockContext context = new ContactsMockContext(getContext());
+ MockContentProvider provider = context.getContactsProvider();
+
+ String inputDisplayName = "prefix given middle family suffix";
+ // The method will ask the provider to split/join StructuredName.
+ Uri uriForBuildDisplayName =
+ ContactsContract.AUTHORITY_URI
+ .buildUpon()
+ .appendPath("complete_name")
+ .appendQueryParameter(StructuredName.DISPLAY_NAME, inputDisplayName)
+ .build();
+ provider.expectQuery(uriForBuildDisplayName)
+ .returnRow("prefix", "given", "middle", "family", "suffix")
+ .withProjection(StructuredName.PREFIX, StructuredName.GIVEN_NAME,
+ StructuredName.MIDDLE_NAME, StructuredName.FAMILY_NAME,
+ StructuredName.SUFFIX);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredName.DISPLAY_NAME, inputDisplayName);
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
+ List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
+ assertEquals(1, list.size());
+
+ ContentValues outputValues = list.get(0).getAfter();
+ assertEquals("prefix", outputValues.getAsString(StructuredName.PREFIX));
+ assertEquals("given", outputValues.getAsString(StructuredName.GIVEN_NAME));
+ assertEquals("middle", outputValues.getAsString(StructuredName.MIDDLE_NAME));
+ assertEquals("family", outputValues.getAsString(StructuredName.FAMILY_NAME));
+ assertEquals("suffix", outputValues.getAsString(StructuredName.SUFFIX));
+ }
+
+ public void testMigrateWithStructuredNameFromExchangeToGoogle() {
+ AccountType oldAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ AccountType newAccountType = new GoogleAccountType(getContext(), "");
+ DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
+
+ ContactsMockContext context = new ContactsMockContext(getContext());
+ MockContentProvider provider = context.getContactsProvider();
+
+ // The method will ask the provider to split/join StructuredName.
+ Uri uriForBuildDisplayName =
+ ContactsContract.AUTHORITY_URI
+ .buildUpon()
+ .appendPath("complete_name")
+ .appendQueryParameter(StructuredName.PREFIX, "prefix")
+ .appendQueryParameter(StructuredName.GIVEN_NAME, "given")
+ .appendQueryParameter(StructuredName.MIDDLE_NAME, "middle")
+ .appendQueryParameter(StructuredName.FAMILY_NAME, "family")
+ .appendQueryParameter(StructuredName.SUFFIX, "suffix")
+ .build();
+ provider.expectQuery(uriForBuildDisplayName)
+ .returnRow("prefix given middle family suffix")
+ .withProjection(StructuredName.DISPLAY_NAME);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredName.PREFIX, "prefix");
+ mockNameValues.put(StructuredName.GIVEN_NAME, "given");
+ mockNameValues.put(StructuredName.MIDDLE_NAME, "middle");
+ mockNameValues.put(StructuredName.FAMILY_NAME, "family");
+ mockNameValues.put(StructuredName.SUFFIX, "suffix");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size());
+ ContentValues outputValues = list.get(0).getAfter();
+ assertEquals("prefix given middle family suffix",
+ outputValues.getAsString(StructuredName.DISPLAY_NAME));
+ }
+
+ public void testMigratePostalFromGoogleToExchange() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredPostal.FORMATTED_ADDRESS, "formatted_address");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migratePostal(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size());
+ ContentValues outputValues = list.get(0).getAfter();
+ // FORMATTED_ADDRESS isn't supported by Exchange.
+ assertNull(outputValues.getAsString(StructuredPostal.FORMATTED_ADDRESS));
+ assertEquals("formatted_address", outputValues.getAsString(StructuredPostal.STREET));
+ }
+
+ public void testMigratePostalFromExchangeToGoogle() {
+ AccountType oldAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ AccountType newAccountType = new GoogleAccountType(getContext(), "");
+ DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
+ mockNameValues.put(StructuredPostal.COUNTRY, "country");
+ mockNameValues.put(StructuredPostal.POSTCODE, "postcode");
+ mockNameValues.put(StructuredPostal.REGION, "region");
+ mockNameValues.put(StructuredPostal.CITY, "city");
+ mockNameValues.put(StructuredPostal.STREET, "street");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migratePostal(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size());
+ ContentValues outputValues = list.get(0).getAfter();
+
+ // Check FORMATTED_ADDRESS contains all info.
+ String formattedAddress = outputValues.getAsString(StructuredPostal.FORMATTED_ADDRESS);
+ assertNotNull(formattedAddress);
+ assertTrue(formattedAddress.contains("country"));
+ assertTrue(formattedAddress.contains("postcode"));
+ assertTrue(formattedAddress.contains("region"));
+ assertTrue(formattedAddress.contains("postcode"));
+ assertTrue(formattedAddress.contains("city"));
+ assertTrue(formattedAddress.contains("street"));
+ }
+
+ public void testMigrateEventFromGoogleToExchange1() {
+ testMigrateEventCommon(new GoogleAccountType(getContext(), ""),
+ new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE));
+ }
+
+ public void testMigrateEventFromExchangeToGoogle() {
+ testMigrateEventCommon(new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE),
+ new GoogleAccountType(getContext(), ""));
+ }
+
+ private void testMigrateEventCommon(AccountType oldAccountType, AccountType newAccountType) {
+ DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Event.START_DATE, "1972-02-08");
+ mockNameValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateEvent(oldState, newState, kind, 1990);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Event.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size()); // Anniversary should be dropped.
+ ContentValues outputValues = list.get(0).getAfter();
+
+ assertEquals("1972-02-08", outputValues.getAsString(Event.START_DATE));
+ assertEquals(Event.TYPE_BIRTHDAY, outputValues.getAsInteger(Event.TYPE).intValue());
+ }
+
+ public void testMigrateEventFromGoogleToExchange2() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
+ // No year format is not supported by Exchange.
+ mockNameValues.put(Event.START_DATE, "--06-01");
+ mockNameValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Event.START_DATE, "1980-08-02");
+ // Anniversary is not supported by Exchange
+ mockNameValues.put(Event.TYPE, Event.TYPE_ANNIVERSARY);
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateEvent(oldState, newState, kind, 1990);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Event.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size()); // Anniversary should be dropped.
+ ContentValues outputValues = list.get(0).getAfter();
+
+ // Default year should be used.
+ assertEquals("1990-06-01", outputValues.getAsString(Event.START_DATE));
+ assertEquals(Event.TYPE_BIRTHDAY, outputValues.getAsInteger(Event.TYPE).intValue());
+ }
+
+ public void testMigrateEmailFromGoogleToExchange() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(Email.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Email.TYPE, Email.TYPE_CUSTOM);
+ mockNameValues.put(Email.LABEL, "custom_type");
+ mockNameValues.put(Email.ADDRESS, "address1");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Email.TYPE, Email.TYPE_HOME);
+ mockNameValues.put(Email.ADDRESS, "address2");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Email.TYPE, Email.TYPE_WORK);
+ mockNameValues.put(Email.ADDRESS, "address3");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ // Exchange can have up to 3 email entries. This 4th entry should be dropped.
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Email.TYPE, Email.TYPE_OTHER);
+ mockNameValues.put(Email.ADDRESS, "address4");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Email.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(3, list.size());
+
+ ContentValues outputValues = list.get(0).getAfter();
+ assertEquals(Email.TYPE_CUSTOM, outputValues.getAsInteger(Email.TYPE).intValue());
+ assertEquals("custom_type", outputValues.getAsString(Email.LABEL));
+ assertEquals("address1", outputValues.getAsString(Email.ADDRESS));
+
+ outputValues = list.get(1).getAfter();
+ assertEquals(Email.TYPE_HOME, outputValues.getAsInteger(Email.TYPE).intValue());
+ assertEquals("address2", outputValues.getAsString(Email.ADDRESS));
+
+ outputValues = list.get(2).getAfter();
+ assertEquals(Email.TYPE_WORK, outputValues.getAsInteger(Email.TYPE).intValue());
+ assertEquals("address3", outputValues.getAsString(Email.ADDRESS));
+ }
+
+ public void testMigrateImFromGoogleToExchange() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(Im.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ // Exchange doesn't support TYPE_HOME
+ mockNameValues.put(Im.TYPE, Im.TYPE_HOME);
+ mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_JABBER);
+ mockNameValues.put(Im.DATA, "im1");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ // Exchange doesn't support TYPE_WORK
+ mockNameValues.put(Im.TYPE, Im.TYPE_WORK);
+ mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_YAHOO);
+ mockNameValues.put(Im.DATA, "im2");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Im.TYPE, Im.TYPE_OTHER);
+ mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM);
+ mockNameValues.put(Im.CUSTOM_PROTOCOL, "custom_protocol");
+ mockNameValues.put(Im.DATA, "im3");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ // Exchange can have up to 3 IM entries. This 4th entry should be dropped.
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Im.TYPE, Im.TYPE_OTHER);
+ mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
+ mockNameValues.put(Im.DATA, "im4");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Im.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(3, list.size());
+
+ assertNotNull(kind.defaultValues.getAsInteger(Im.TYPE));
+
+ int defaultType = kind.defaultValues.getAsInteger(Im.TYPE);
+
+ ContentValues outputValues = list.get(0).getAfter();
+ // HOME should become default type.
+ assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
+ assertEquals(Im.PROTOCOL_JABBER, outputValues.getAsInteger(Im.PROTOCOL).intValue());
+ assertEquals("im1", outputValues.getAsString(Im.DATA));
+
+ outputValues = list.get(1).getAfter();
+ assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
+ assertEquals(Im.PROTOCOL_YAHOO, outputValues.getAsInteger(Im.PROTOCOL).intValue());
+ assertEquals("im2", outputValues.getAsString(Im.DATA));
+
+ outputValues = list.get(2).getAfter();
+ assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
+ assertEquals(Im.PROTOCOL_CUSTOM, outputValues.getAsInteger(Im.PROTOCOL).intValue());
+ assertEquals("custom_protocol", outputValues.getAsString(Im.CUSTOM_PROTOCOL));
+ assertEquals("im3", outputValues.getAsString(Im.DATA));
+ }
+
+ public void testMigratePhoneFromGoogleToExchange() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+
+ // Create 5 numbers.
+ // - "1" -- HOME
+ // - "2" -- WORK
+ // - "3" -- CUSTOM
+ // - "4" -- WORK
+ // - "5" -- WORK_MOBILE
+ // Then we convert it to Exchange account type.
+ // - "1" -- HOME
+ // - "2" -- WORK
+ // - "3" -- Because CUSTOM is not supported, it'll be changed to the default, MOBILE
+ // - "4" -- WORK
+ // - "5" -- WORK_MOBILE not suppoted again, so will be MOBILE.
+ // But then, Exchange doesn't support multiple MOBILE numbers, so "5" will be removed.
+ // i.e. the result will be:
+ // - "1" -- HOME
+ // - "2" -- WORK
+ // - "3" -- MOBILE
+ // - "4" -- WORK
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Phone.TYPE, Phone.TYPE_HOME);
+ mockNameValues.put(Phone.NUMBER, "1");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK);
+ mockNameValues.put(Phone.NUMBER, "2");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ // Exchange doesn't support this type. Default to MOBILE
+ mockNameValues.put(Phone.TYPE, Phone.TYPE_CUSTOM);
+ mockNameValues.put(Phone.LABEL, "custom_type");
+ mockNameValues.put(Phone.NUMBER, "3");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK);
+ mockNameValues.put(Phone.NUMBER, "4");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+ mockNameValues = new ContentValues();
+
+ mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK_MOBILE);
+ mockNameValues.put(Phone.NUMBER, "5");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(4, list.size());
+
+ int defaultType = Phone.TYPE_MOBILE;
+
+ ContentValues outputValues = list.get(0).getAfter();
+ assertEquals(Phone.TYPE_HOME, outputValues.getAsInteger(Phone.TYPE).intValue());
+ assertEquals("1", outputValues.getAsString(Phone.NUMBER));
+ outputValues = list.get(1).getAfter();
+ assertEquals(Phone.TYPE_WORK, outputValues.getAsInteger(Phone.TYPE).intValue());
+ assertEquals("2", outputValues.getAsString(Phone.NUMBER));
+ outputValues = list.get(2).getAfter();
+ assertEquals(defaultType, outputValues.getAsInteger(Phone.TYPE).intValue());
+ assertNull(outputValues.getAsInteger(Phone.LABEL));
+ assertEquals("3", outputValues.getAsString(Phone.NUMBER));
+ outputValues = list.get(3).getAfter();
+ assertEquals(Phone.TYPE_WORK, outputValues.getAsInteger(Phone.TYPE).intValue());
+ assertEquals("4", outputValues.getAsString(Phone.NUMBER));
+ }
+
+ public void testMigrateOrganizationFromGoogleToExchange() {
+ AccountType oldAccountType = new GoogleAccountType(getContext(), "");
+ AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
+ DataKind kind = newAccountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
+
+ RawContactDelta oldState = new RawContactDelta();
+ ContentValues mockNameValues = new ContentValues();
+ mockNameValues.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
+ mockNameValues.put(Organization.COMPANY, "company1");
+ mockNameValues.put(Organization.DEPARTMENT, "department1");
+ oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
+
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithoutTypeColumn(oldState, newState, kind);
+
+ List<ValuesDelta> list = newState.getMimeEntries(Organization.CONTENT_ITEM_TYPE);
+ assertNotNull(list);
+ assertEquals(1, list.size());
+
+ ContentValues outputValues = list.get(0).getAfter();
+ assertEquals("company1", outputValues.getAsString(Organization.COMPANY));
+ assertEquals("department1", outputValues.getAsString(Organization.DEPARTMENT));
+ }
+}
diff --git a/tests/src/com/android/contacts/common/compat/CompatUtilsTest.java b/tests/src/com/android/contacts/common/compat/CompatUtilsTest.java
new file mode 100644
index 0000000..3386a00
--- /dev/null
+++ b/tests/src/com/android/contacts/common/compat/CompatUtilsTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 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.common.compat;
+
+import android.test.AndroidTestCase;
+
+public class CompatUtilsTest extends AndroidTestCase {
+
+ public void testIsClassAvailable_NullClassName() {
+ assertFalse(CompatUtils.isClassAvailable(null));
+ }
+
+ public void testIsClassAvailable_EmptyClassName() {
+ assertFalse(CompatUtils.isClassAvailable(""));
+ }
+
+ public void testIsClassAvailable_NonexistentClass() {
+ assertFalse(CompatUtils.isClassAvailable("com.android.contacts.common.NonexistentClass"));
+ }
+
+ public void testIsClassAvailable() {
+ assertTrue(CompatUtils.isClassAvailable(BaseClass.class.getName()));
+ }
+
+ public void testIsMethodAvailable_NullClassName() {
+ assertFalse(CompatUtils.isMethodAvailable(null, "methodName"));
+ }
+
+ public void testIsMethodAvailable_EmptyClassName() {
+ assertFalse(CompatUtils.isMethodAvailable("", "methodName"));
+ }
+
+ public void testIsMethodAvailable_NullMethodName() {
+ assertFalse(CompatUtils.isMethodAvailable("className", null));
+ }
+
+ public void testIsMethodAvailable_EmptyMethodName() {
+ assertFalse(CompatUtils.isMethodAvailable("className", ""));
+ }
+
+ public void testIsMethodAvailable_NonexistentClass() {
+ assertFalse(CompatUtils.isMethodAvailable("com.android.contacts.common.NonexistentClass",
+ ""));
+ }
+
+ public void testIsMethodAvailable_NonexistentMethod() {
+ assertFalse(CompatUtils.isMethodAvailable(BaseClass.class.getName(), "derivedMethod"));
+ }
+
+ public void testIsMethodAvailable() {
+ assertTrue(CompatUtils.isMethodAvailable(BaseClass.class.getName(), "baseMethod"));
+ }
+
+ public void testIsMethodAvailable_InheritedMethod() {
+ assertTrue(CompatUtils.isMethodAvailable(DerivedClass.class.getName(), "baseMethod"));
+ }
+
+ public void testIsMethodAvailable_OverloadedMethod() {
+ assertTrue(CompatUtils.isMethodAvailable(DerivedClass.class.getName(), "overloadedMethod"));
+ assertTrue(CompatUtils.isMethodAvailable(DerivedClass.class.getName(), "overloadedMethod",
+ Integer.TYPE));
+ }
+
+ public void testIsMethodAvailable_NonexistentOverload() {
+ assertFalse(CompatUtils.isMethodAvailable(DerivedClass.class.getName(), "overloadedMethod",
+ Boolean.TYPE));
+ }
+
+ public void testInvokeMethod_NullMethodName() {
+ assertNull(CompatUtils.invokeMethod(new BaseClass(), null, null, null));
+ }
+
+ public void testInvokeMethod_EmptyMethodName() {
+ assertNull(CompatUtils.invokeMethod(new BaseClass(), "", null, null));
+ }
+
+ public void testInvokeMethod_NullClassInstance() {
+ assertNull(CompatUtils.invokeMethod(null, "", null, null));
+ }
+
+ public void testInvokeMethod_NonexistentMethod() {
+ assertNull(CompatUtils.invokeMethod(new BaseClass(), "derivedMethod", null, null));
+ }
+
+ public void testInvokeMethod_MethodWithNoParameters() {
+ assertEquals(1, CompatUtils.invokeMethod(new DerivedClass(), "overloadedMethod", null, null));
+ }
+
+ public void testInvokeMethod_MethodWithNoParameters_WithParameters() {
+ assertNull(CompatUtils.invokeMethod(new DerivedClass(), "derivedMethod",
+ new Class<?>[] {Integer.TYPE}, new Object[] {1}));
+ }
+
+ public void testInvokeMethod_MethodWithParameters_WithEmptyParameterList() {
+ assertNull(CompatUtils.invokeMethod(new DerivedClass(), "overloadedMethod",
+ new Class<?>[] {Integer.TYPE}, new Object[] {}));
+ }
+
+ public void testInvokeMethod_InvokeSimpleMethod() {
+ assertEquals(2, CompatUtils.invokeMethod(new DerivedClass(), "overloadedMethod",
+ new Class<?>[] {Integer.TYPE}, new Object[] {2}));
+ }
+
+ private class BaseClass {
+ public void baseMethod() {}
+ }
+
+ private class DerivedClass extends BaseClass {
+ public int derivedMethod() {
+ // This method needs to return something to differentiate a successful invocation from
+ // an unsuccessful one.
+ return 0;
+ }
+
+ public int overloadedMethod() {
+ return 1;
+ }
+
+ public int overloadedMethod(int i) {
+ return i;
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/common/database/NoNullCursorAsyncQueryHandlerTest.java b/tests/src/com/android/contacts/common/database/NoNullCursorAsyncQueryHandlerTest.java
new file mode 100644
index 0000000..a2b635d
--- /dev/null
+++ b/tests/src/com/android/contacts/common/database/NoNullCursorAsyncQueryHandlerTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2012 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.common.database;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.test.InstrumentationTestCase;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Unit test for {@link NoNullCursorAsyncQueryHandler}
+ */
+public class NoNullCursorAsyncQueryHandlerTest extends InstrumentationTestCase {
+
+ private MockContentResolver mMockContentResolver;
+
+ private static final String AUTHORITY = "com.android.contacts.common.unittest";
+ private static final Uri URI = Uri.parse("content://" + AUTHORITY);
+ private static final String[] PROJECTION = new String[]{"column1", "column2"};
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mMockContentResolver = new MockContentResolver();
+ final MockContentProvider mMockContentProvider = new MockContentProvider() {
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+ };
+
+ mMockContentResolver.addProvider(AUTHORITY, mMockContentProvider);
+ }
+
+ public void testCursorIsNotNull() throws Throwable {
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ObjectHolder<Cursor> cursorHolder = ObjectHolder.newInstance();
+ final ObjectHolder<Boolean> ranHolder = ObjectHolder.newInstance(false);
+
+ runTestOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+
+ NoNullCursorAsyncQueryHandler handler = new NoNullCursorAsyncQueryHandler(
+ mMockContentResolver) {
+ @Override
+ protected void onNotNullableQueryComplete(int token, Object cookie,
+ Cursor cursor) {
+ cursorHolder.obj = cursor;
+ ranHolder.obj = true;
+ latch.countDown();
+ }
+ };
+ handler.startQuery(1, null, URI, PROJECTION, null, null, null);
+ }
+ });
+
+ latch.await(5, TimeUnit.SECONDS);
+ assertFalse(cursorHolder.obj == null);
+ assertTrue(ranHolder.obj);
+ }
+
+ public void testCursorContainsCorrectCookies() throws Throwable {
+ final ObjectHolder<Boolean> ranHolder = ObjectHolder.newInstance(false);
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ObjectHolder<Object> cookieHolder = ObjectHolder.newInstance();
+ final String cookie = "TEST COOKIE";
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final NoNullCursorAsyncQueryHandler handler = new NoNullCursorAsyncQueryHandler(
+ mMockContentResolver) {
+ @Override
+ protected void onNotNullableQueryComplete(int token, Object cookie,
+ Cursor cursor) {
+ ranHolder.obj = true;
+ cookieHolder.obj = cookie;
+ latch.countDown();
+ }
+ };
+ handler.startQuery(1, cookie, URI, PROJECTION, null, null, null);
+ }
+ });
+
+ latch.await(5, TimeUnit.SECONDS);
+ assertSame(cookie, cookieHolder.obj);
+ assertTrue(ranHolder.obj);
+ }
+
+ public void testCursorContainsCorrectColumns() throws Throwable {
+ final ObjectHolder<Boolean> ranHolder = ObjectHolder.newInstance(false);
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ObjectHolder<Cursor> cursorHolder = ObjectHolder.newInstance();
+ final String cookie = "TEST COOKIE";
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final NoNullCursorAsyncQueryHandler handler = new NoNullCursorAsyncQueryHandler(
+ mMockContentResolver) {
+ @Override
+ protected void onNotNullableQueryComplete(int token, Object cookie,
+ Cursor cursor) {
+ ranHolder.obj = true;
+ cursorHolder.obj = cursor;
+ latch.countDown();
+ }
+ };
+ handler.startQuery(1, cookie, URI, PROJECTION, null, null, null);
+ }
+ });
+
+ latch.await(5, TimeUnit.SECONDS);
+ assertSame(PROJECTION, cursorHolder.obj.getColumnNames());
+ assertTrue(ranHolder.obj);
+ }
+
+ private static class ObjectHolder<T> {
+ public T obj;
+
+ public static <E> ObjectHolder<E> newInstance() {
+ return new ObjectHolder<E>();
+ }
+
+ public static <E> ObjectHolder<E> newInstance(E value) {
+ ObjectHolder<E> holder = new ObjectHolder<E>();
+ holder.obj = value;
+ return holder;
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/common/format/FormatUtilsTests.java b/tests/src/com/android/contacts/common/format/FormatUtilsTests.java
new file mode 100644
index 0000000..8f4f772
--- /dev/null
+++ b/tests/src/com/android/contacts/common/format/FormatUtilsTests.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2011 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.common.format;
+
+import android.database.CharArrayBuffer;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Test cases for format utility methods.
+ */
+@SmallTest
+public class FormatUtilsTests extends AndroidTestCase {
+
+ public void testOverlapPoint() throws Exception {
+ assertEquals(2, FormatUtils.overlapPoint("abcde", "cdefg"));
+ assertEquals(-1, FormatUtils.overlapPoint("John Doe", "John Doe"));
+ assertEquals(5, FormatUtils.overlapPoint("John Doe", "Doe, John"));
+ assertEquals(-1, FormatUtils.overlapPoint("Mr. John Doe", "Mr. Doe, John"));
+ assertEquals(13, FormatUtils.overlapPoint("John Herbert Doe", "Doe, John Herbert"));
+ }
+
+ public void testCopyToCharArrayBuffer() {
+ CharArrayBuffer charArrayBuffer = new CharArrayBuffer(20);
+ checkCopyToCharArrayBuffer(charArrayBuffer, null, 0);
+ checkCopyToCharArrayBuffer(charArrayBuffer, "", 0);
+ checkCopyToCharArrayBuffer(charArrayBuffer, "test", 4);
+ // Check that it works after copying something into it.
+ checkCopyToCharArrayBuffer(charArrayBuffer, "", 0);
+ checkCopyToCharArrayBuffer(charArrayBuffer, "test", 4);
+ checkCopyToCharArrayBuffer(charArrayBuffer, null, 0);
+ // This requires a resize of the actual buffer.
+ checkCopyToCharArrayBuffer(charArrayBuffer, "test test test test test", 24);
+ }
+
+ public void testCharArrayBufferToString() {
+ checkCharArrayBufferToString("");
+ checkCharArrayBufferToString("test");
+ checkCharArrayBufferToString("test test test test test");
+ }
+
+ /** Checks that copying a string into a {@link CharArrayBuffer} and back works correctly. */
+ private void checkCharArrayBufferToString(String text) {
+ CharArrayBuffer buffer = new CharArrayBuffer(20);
+ FormatUtils.copyToCharArrayBuffer(text, buffer);
+ assertEquals(text, FormatUtils.charArrayBufferToString(buffer));
+ }
+
+ /**
+ * Checks that copying into the char array buffer copies the values correctly.
+ */
+ private void checkCopyToCharArrayBuffer(CharArrayBuffer buffer, String value, int length) {
+ FormatUtils.copyToCharArrayBuffer(value, buffer);
+ assertEquals(length, buffer.sizeCopied);
+ for (int index = 0; index < length; ++index) {
+ assertEquals(value.charAt(index), buffer.data[index]);
+ }
+ }
+
+ public void testIndexOfWordPrefix_NullPrefix() {
+ assertEquals(-1, FormatUtils.indexOfWordPrefix("test", null));
+ }
+
+ public void testIndexOfWordPrefix_NullText() {
+ assertEquals(-1, FormatUtils.indexOfWordPrefix(null, "TE"));
+ }
+
+ public void testIndexOfWordPrefix_MatchingPrefix() {
+ checkIndexOfWordPrefix("test", "TE", 0);
+ checkIndexOfWordPrefix("Test", "TE", 0);
+ checkIndexOfWordPrefix("TEst", "TE", 0);
+ checkIndexOfWordPrefix("TEST", "TE", 0);
+ checkIndexOfWordPrefix("a test", "TE", 2);
+ checkIndexOfWordPrefix("test test", "TE", 0);
+ checkIndexOfWordPrefix("a test test", "TE", 2);
+ }
+
+ public void testIndexOfWordPrefix_NotMatchingPrefix() {
+ checkIndexOfWordPrefix("test", "TA", -1);
+ checkIndexOfWordPrefix("test type theme", "TA", -1);
+ checkIndexOfWordPrefix("atest retest pretest", "TEST", -1);
+ checkIndexOfWordPrefix("tes", "TEST", -1);
+ }
+
+ public void testIndexOfWordPrefix_LowerCase() {
+ // The prefix match only works if the prefix is un upper case.
+ checkIndexOfWordPrefix("test", "te", -1);
+ }
+
+ /**
+ * Checks that getting the index of a word prefix in the given text returns the expected index.
+ *
+ * @param text the text in which to look for the word
+ * @param wordPrefix the word prefix to look for
+ * @param expectedIndex the expected value to be returned by the function
+ */
+ private void checkIndexOfWordPrefix(String text, String wordPrefix, int expectedIndex) {
+ assertEquals(expectedIndex, FormatUtils.indexOfWordPrefix(text, wordPrefix));
+ }
+}
diff --git a/tests/src/com/android/contacts/common/format/TextHighlighterTest.java b/tests/src/com/android/contacts/common/format/TextHighlighterTest.java
new file mode 100644
index 0000000..7bf28c5
--- /dev/null
+++ b/tests/src/com/android/contacts/common/format/TextHighlighterTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2011 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.common.format;
+
+import android.graphics.Typeface;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.SpannableString;
+
+import com.android.contacts.common.format.SpannedTestUtils;
+import com.android.contacts.common.format.TextHighlighter;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link TextHighlighter}.
+ */
+@SmallTest
+public class TextHighlighterTest extends TestCase {
+ private static final int TEST_PREFIX_HIGHLIGHT_COLOR = 0xFF0000;
+
+ /** The object under test. */
+ private TextHighlighter mTextHighlighter;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mTextHighlighter = new TextHighlighter(Typeface.BOLD);
+ }
+
+ public void testApply_EmptyPrefix() {
+ CharSequence seq = mTextHighlighter.applyPrefixHighlight("", "");
+ SpannedTestUtils.assertNotSpanned(seq, "");
+
+ seq = mTextHighlighter.applyPrefixHighlight("test", "");
+ SpannedTestUtils.assertNotSpanned(seq, "test");
+ }
+
+ public void testSetText_MatchingPrefix() {
+ final String prefix = "TE";
+
+ CharSequence seq = mTextHighlighter.applyPrefixHighlight("test", prefix);
+ SpannedTestUtils.assertPrefixSpan(seq, 0, 1);
+
+ seq = mTextHighlighter.applyPrefixHighlight("Test", prefix);
+ SpannedTestUtils.assertPrefixSpan(seq, 0, 1);
+
+ seq = mTextHighlighter.applyPrefixHighlight("TEst", prefix);
+ SpannedTestUtils.assertPrefixSpan(seq, 0, 1);
+
+ seq = mTextHighlighter.applyPrefixHighlight("a test", prefix);
+ SpannedTestUtils.assertPrefixSpan(seq, 2, 3);
+ }
+
+ public void testSetText_NotMatchingPrefix() {
+ final CharSequence seq = mTextHighlighter.applyPrefixHighlight("test", "TA");
+ SpannedTestUtils.assertNotSpanned(seq, "test");
+ }
+
+ public void testSetText_FirstMatch() {
+ final CharSequence seq = mTextHighlighter.applyPrefixHighlight(
+ "a test's tests are not tests", "TE");
+ SpannedTestUtils.assertPrefixSpan(seq, 2, 3);
+ }
+
+ public void testSetText_NoMatchingMiddleOfWord() {
+ final String prefix = "TE";
+ CharSequence seq = mTextHighlighter.applyPrefixHighlight("atest", prefix);
+ SpannedTestUtils.assertNotSpanned(seq, "atest");
+
+ seq = mTextHighlighter.applyPrefixHighlight("atest otest", prefix);
+ SpannedTestUtils.assertNotSpanned(seq, "atest otest");
+
+ seq = mTextHighlighter.applyPrefixHighlight("atest test", prefix);
+ SpannedTestUtils.assertPrefixSpan(seq, 6, 7);
+ }
+
+ public void testSetMask_Highlight() {
+ final SpannableString testString1 = new SpannableString("alongtest");
+ mTextHighlighter.applyMaskingHighlight(testString1, 2, 4);
+ assertEquals(2, SpannedTestUtils.getNextTransition(testString1, 0));
+ assertEquals(4, SpannedTestUtils.getNextTransition(testString1, 2));
+
+ mTextHighlighter.applyMaskingHighlight(testString1, 3, 6);
+ assertEquals(2, SpannedTestUtils.getNextTransition(testString1, 0));
+ assertEquals(4, SpannedTestUtils.getNextTransition(testString1, 3));
+
+ mTextHighlighter.applyMaskingHighlight(testString1, 4, 5);
+ assertEquals(3, SpannedTestUtils.getNextTransition(testString1, 2));
+
+ mTextHighlighter.applyMaskingHighlight(testString1, 7, 8);
+ assertEquals(6, SpannedTestUtils.getNextTransition(testString1, 5));
+ assertEquals(7, SpannedTestUtils.getNextTransition(testString1, 6));
+ assertEquals(8, SpannedTestUtils.getNextTransition(testString1, 7));
+ }
+}
diff --git a/tests/src/com/android/contacts/common/list/ContactListItemViewTest.java b/tests/src/com/android/contacts/common/list/ContactListItemViewTest.java
new file mode 100644
index 0000000..c9b2e6d
--- /dev/null
+++ b/tests/src/com/android/contacts/common/list/ContactListItemViewTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2011 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.common.list;
+
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.ContactsContract;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.widget.TextView;
+
+import com.android.contacts.common.format.SpannedTestUtils;
+import com.android.contacts.common.list.ContactListItemView;
+import com.android.contacts.common.preference.ContactsPreferences;
+
+/**
+ * Unit tests for {@link com.android.contacts.common.list.ContactListItemView}.
+ *
+ * It uses an {@link ActivityInstrumentationTestCase2} for {@link PeopleActivity} because we need
+ * to have the style properly setup.
+ */
+@LargeTest
+public class ContactListItemViewTest extends AndroidTestCase {
+
+ //private IntegrationTestUtils mUtils;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // This test requires that the screen be turned on.
+ //mUtils = new IntegrationTestUtils(getInstrumentation());
+ //mUtils.acquireScreenWakeLock(getInstrumentation().getTargetContext());
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ //mUtils.releaseScreenWakeLock();
+ super.tearDown();
+ }
+
+ public void testShowDisplayName_Simple() {
+ Cursor cursor = createCursor("John Doe", "Doe John");
+ ContactListItemView view = createView();
+
+ view.showDisplayName(cursor, 0, ContactsPreferences.DISPLAY_ORDER_PRIMARY);
+
+ assertEquals(view.getNameTextView().getText().toString(), "John Doe");
+ }
+
+ public void testShowDisplayName_Unknown() {
+ Cursor cursor = createCursor("", "");
+ ContactListItemView view = createView();
+
+ view.setUnknownNameText("unknown");
+ view.showDisplayName(cursor, 0, ContactsPreferences.DISPLAY_ORDER_PRIMARY);
+
+ assertEquals(view.getNameTextView().getText().toString(), "unknown");
+ }
+
+ public void testShowDisplayName_WithPrefix() {
+ Cursor cursor = createCursor("John Doe", "Doe John");
+ ContactListItemView view = createView();
+
+ view.setHighlightedPrefix("DOE");
+ view.showDisplayName(cursor, 0, ContactsPreferences.DISPLAY_ORDER_PRIMARY);
+
+ CharSequence seq = view.getNameTextView().getText();
+ assertEquals("John Doe", seq.toString());
+ SpannedTestUtils.assertPrefixSpan(seq, 5, 7);
+ // Talback should be without span tags.
+ assertEquals("John Doe", view.getNameTextView().getContentDescription());
+ assertFalse("John Doe".equals(seq));
+ }
+
+ public void testShowDisplayName_WithPrefixReversed() {
+ Cursor cursor = createCursor("John Doe", "Doe John");
+ ContactListItemView view = createView();
+
+ view.setHighlightedPrefix("DOE");
+ view.showDisplayName(cursor, 0, ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE);
+
+ CharSequence seq = view.getNameTextView().getText();
+ assertEquals("John Doe", seq.toString());
+ SpannedTestUtils.assertPrefixSpan(seq, 5, 7);
+ }
+
+ public void testSetSnippet_Prefix() {
+ ContactListItemView view = createView();
+ view.setHighlightedPrefix("TEST");
+ view.setSnippet("This is a test");
+
+ CharSequence seq = view.getSnippetView().getText();
+
+ assertEquals("This is a test", seq.toString());
+ SpannedTestUtils.assertPrefixSpan(seq, 10, 13);
+ }
+
+ /** Creates the view to be tested. */
+ private ContactListItemView createView() {
+ ContactListItemView view = new ContactListItemView(getContext());
+ // Set the name view to use a Spannable to represent its content.
+ view.getNameTextView().setText("", TextView.BufferType.SPANNABLE);
+ return view;
+ }
+
+ /**
+ * Creates a cursor containing a pair of values.
+ *
+ * @param name the name to insert in the first column of the cursor
+ * @param alternateName the alternate name to insert in the second column of the cursor
+ * @return the newly created cursor
+ */
+ private Cursor createCursor(String name, String alternateName) {
+ MatrixCursor cursor = new MatrixCursor(new String[]{"Name", "AlternateName"});
+ cursor.moveToFirst();
+ cursor.addRow(new Object[]{name, alternateName});
+ return cursor;
+ }
+}
diff --git a/tests/src/com/android/contacts/common/model/AccountTypeManagerTest.java b/tests/src/com/android/contacts/common/model/AccountTypeManagerTest.java
new file mode 100644
index 0000000..b8ebdd2
--- /dev/null
+++ b/tests/src/com/android/contacts/common/model/AccountTypeManagerTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2011 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.common.model;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountTypeWithDataSet;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Test case for {@link com.android.contacts.common.model.AccountTypeManager}.
+ *
+ * adb shell am instrument -w -e class com.android.contacts.model.AccountTypeManagerTest \
+ com.android.contacts.tests/android.test.InstrumentationTestRunner
+ */
+@SmallTest
+public class AccountTypeManagerTest extends AndroidTestCase {
+ public void testFindAllInvitableAccountTypes() {
+ final Context c = getContext();
+
+ // Define account types.
+ final AccountType typeA = new MockAccountType("type1", null, null);
+ final AccountType typeB = new MockAccountType("type1", "minus", null);
+ final AccountType typeC = new MockAccountType("type2", null, "c");
+ final AccountType typeD = new MockAccountType("type2", "minus", "d");
+
+ // Define users
+ final AccountWithDataSet accountA1 = createAccountWithDataSet("a1", typeA);
+ final AccountWithDataSet accountC1 = createAccountWithDataSet("c1", typeC);
+ final AccountWithDataSet accountC2 = createAccountWithDataSet("c2", typeC);
+ final AccountWithDataSet accountD1 = createAccountWithDataSet("d1", typeD);
+
+ // empty - empty
+ Map<AccountTypeWithDataSet, AccountType> types =
+ AccountTypeManagerImpl.findAllInvitableAccountTypes(c,
+ buildAccounts(), buildAccountTypes());
+ assertEquals(0, types.size());
+ try {
+ types.clear();
+ fail("Returned Map should be unmodifiable.");
+ } catch (UnsupportedOperationException ok) {
+ }
+
+ // No invite support, no accounts
+ verifyAccountTypes(
+ buildAccounts(),
+ buildAccountTypes(typeA, typeB)
+ /* empty */
+ );
+
+ // No invite support, with accounts
+ verifyAccountTypes(
+ buildAccounts(accountA1),
+ buildAccountTypes(typeA)
+ /* empty */
+ );
+
+ // With invite support, no accounts
+ verifyAccountTypes(
+ buildAccounts(),
+ buildAccountTypes(typeC)
+ /* empty */
+ );
+
+ // With invite support, 1 account
+ verifyAccountTypes(
+ buildAccounts(accountC1),
+ buildAccountTypes(typeC),
+ typeC
+ );
+
+ // With invite support, 2 account
+ verifyAccountTypes(
+ buildAccounts(accountC1, accountC2),
+ buildAccountTypes(typeC),
+ typeC
+ );
+
+ // Combinations...
+ verifyAccountTypes(
+ buildAccounts(accountA1),
+ buildAccountTypes(typeA, typeC)
+ /* empty */
+ );
+
+ verifyAccountTypes(
+ buildAccounts(accountC1, accountA1),
+ buildAccountTypes(typeA, typeC),
+ typeC
+ );
+
+ verifyAccountTypes(
+ buildAccounts(accountC1, accountA1),
+ buildAccountTypes(typeD, typeA, typeC),
+ typeC
+ );
+
+ verifyAccountTypes(
+ buildAccounts(accountC1, accountA1, accountD1),
+ buildAccountTypes(typeD, typeA, typeC, typeB),
+ typeC, typeD
+ );
+ }
+
+ private static AccountWithDataSet createAccountWithDataSet(String name, AccountType type) {
+ return new AccountWithDataSet(name, type.accountType, type.dataSet);
+ }
+
+ /**
+ * Array of {@link AccountType} -> {@link Map}
+ */
+ private static Map<AccountTypeWithDataSet, AccountType> buildAccountTypes(AccountType... types) {
+ final HashMap<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap();
+ for (AccountType type : types) {
+ result.put(type.getAccountTypeAndDataSet(), type);
+ }
+ return result;
+ }
+
+ /**
+ * Array of {@link AccountWithDataSet} -> {@link Collection}
+ */
+ private static Collection<AccountWithDataSet> buildAccounts(AccountWithDataSet... accounts) {
+ final List<AccountWithDataSet> result = Lists.newArrayList();
+ for (AccountWithDataSet account : accounts) {
+ result.add(account);
+ }
+ return result;
+ }
+
+ /**
+ * Executes {@link AccountTypeManagerImpl#findInvitableAccountTypes} and verifies the
+ * result.
+ */
+ private void verifyAccountTypes(
+ Collection<AccountWithDataSet> accounts,
+ Map<AccountTypeWithDataSet, AccountType> types,
+ AccountType... expectedInvitableTypes
+ ) {
+ Map<AccountTypeWithDataSet, AccountType> result =
+ AccountTypeManagerImpl.findAllInvitableAccountTypes(getContext(), accounts, types);
+ for (AccountType type : expectedInvitableTypes) {
+ assertTrue("Result doesn't contain type=" + type.getAccountTypeAndDataSet(),
+ result.containsKey(type.getAccountTypeAndDataSet()));
+ }
+ final int numExcessTypes = result.size() - expectedInvitableTypes.length;
+ assertEquals("Result contains " + numExcessTypes + " excess type(s)", 0, numExcessTypes);
+ }
+
+ private static class MockAccountType extends AccountType {
+ private final String mInviteContactActivityClassName;
+
+ public MockAccountType(String type, String dataSet, String inviteContactActivityClassName) {
+ accountType = type;
+ this.dataSet = dataSet;
+ mInviteContactActivityClassName = inviteContactActivityClassName;
+ }
+
+ @Override
+ public String getInviteContactActivityClassName() {
+ return mInviteContactActivityClassName;
+ }
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return false;
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return false;
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/common/model/AccountWithDataSetTest.java b/tests/src/com/android/contacts/common/model/AccountWithDataSetTest.java
new file mode 100644
index 0000000..e28f09e
--- /dev/null
+++ b/tests/src/com/android/contacts/common/model/AccountWithDataSetTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2011 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.common.model;
+
+import android.os.Bundle;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Test case for {@link AccountWithDataSet}.
+ *
+ * adb shell am instrument -w -e class com.android.contacts.model.AccountWithDataSetTest \
+ com.android.contacts.tests/android.test.InstrumentationTestRunner
+ */
+@SmallTest
+public class AccountWithDataSetTest extends AndroidTestCase {
+ public void testStringifyAndUnstringify() {
+ AccountWithDataSet a1 = new AccountWithDataSet("name1", "typeA", null);
+ AccountWithDataSet a2 = new AccountWithDataSet("name2", "typeB", null);
+ AccountWithDataSet a3 = new AccountWithDataSet("name3", "typeB", "dataset");
+
+ // stringify() & unstringify
+ AccountWithDataSet a1r = AccountWithDataSet.unstringify(a1.stringify());
+ AccountWithDataSet a2r = AccountWithDataSet.unstringify(a2.stringify());
+ AccountWithDataSet a3r = AccountWithDataSet.unstringify(a3.stringify());
+
+ assertEquals(a1, a1r);
+ assertEquals(a2, a2r);
+ assertEquals(a3, a3r);
+
+ MoreAsserts.assertNotEqual(a1, a2r);
+ MoreAsserts.assertNotEqual(a1, a3r);
+
+ MoreAsserts.assertNotEqual(a2, a1r);
+ MoreAsserts.assertNotEqual(a2, a3r);
+
+ MoreAsserts.assertNotEqual(a3, a1r);
+ MoreAsserts.assertNotEqual(a3, a2r);
+ }
+
+ public void testStringifyListAndUnstringify() {
+ AccountWithDataSet a1 = new AccountWithDataSet("name1", "typeA", null);
+ AccountWithDataSet a2 = new AccountWithDataSet("name2", "typeB", null);
+ AccountWithDataSet a3 = new AccountWithDataSet("name3", "typeB", "dataset");
+
+ // Empty list
+ assertEquals(0, stringifyListAndUnstringify().size());
+
+ // 1 element
+ final List<AccountWithDataSet> listA = stringifyListAndUnstringify(a1);
+ assertEquals(1, listA.size());
+ assertEquals(a1, listA.get(0));
+
+ // 2 elements
+ final List<AccountWithDataSet> listB = stringifyListAndUnstringify(a2, a1);
+ assertEquals(2, listB.size());
+ assertEquals(a2, listB.get(0));
+ assertEquals(a1, listB.get(1));
+
+ // 3 elements
+ final List<AccountWithDataSet> listC = stringifyListAndUnstringify(a3, a2, a1);
+ assertEquals(3, listC.size());
+ assertEquals(a3, listC.get(0));
+ assertEquals(a2, listC.get(1));
+ assertEquals(a1, listC.get(2));
+ }
+
+ private static List<AccountWithDataSet> stringifyListAndUnstringify(
+ AccountWithDataSet... accounts) {
+
+ List<AccountWithDataSet> list = Lists.newArrayList(accounts);
+ return AccountWithDataSet.unstringifyList(AccountWithDataSet.stringifyList(list));
+ }
+
+ public void testParcelable() {
+ AccountWithDataSet a1 = new AccountWithDataSet("name1", "typeA", null);
+ AccountWithDataSet a2 = new AccountWithDataSet("name2", "typeB", null);
+ AccountWithDataSet a3 = new AccountWithDataSet("name3", "typeB", "dataset");
+
+ // Parcel them & unpercel.
+ final Bundle b = new Bundle();
+ b.putParcelable("a1", a1);
+ b.putParcelable("a2", a2);
+ b.putParcelable("a3", a3);
+
+ AccountWithDataSet a1r = b.getParcelable("a1");
+ AccountWithDataSet a2r = b.getParcelable("a2");
+ AccountWithDataSet a3r = b.getParcelable("a3");
+
+ assertEquals(a1, a1r);
+ assertEquals(a2, a2r);
+ assertEquals(a3, a3r);
+
+ MoreAsserts.assertNotEqual(a1, a2r);
+ MoreAsserts.assertNotEqual(a1, a3r);
+
+ MoreAsserts.assertNotEqual(a2, a1r);
+ MoreAsserts.assertNotEqual(a2, a3r);
+
+ MoreAsserts.assertNotEqual(a3, a1r);
+ MoreAsserts.assertNotEqual(a3, a2r);
+ }
+}
diff --git a/tests/src/com/android/contacts/common/model/ContactLoaderTest.java b/tests/src/com/android/contacts/common/model/ContactLoaderTest.java
new file mode 100644
index 0000000..9878a12
--- /dev/null
+++ b/tests/src/com/android/contacts/common/model/ContactLoaderTest.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2010 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.common.model;
+
+import android.content.ContentUris;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.DisplayNameSources;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.StatusUpdates;
+import android.test.LoaderTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.BaseAccountType;
+import com.android.contacts.common.testing.InjectedServices;
+import com.android.contacts.common.test.mocks.ContactsMockContext;
+import com.android.contacts.common.test.mocks.MockContentProvider;
+import com.android.contacts.common.test.mocks.MockContentProvider.Query;
+import com.android.contacts.common.test.mocks.MockAccountTypeManager;
+import com.android.contacts.common.util.Constants;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Runs ContactLoader tests for the the contact-detail and editor view.
+ */
+@LargeTest
+public class ContactLoaderTest extends LoaderTestCase {
+ private static final long CONTACT_ID = 1;
+ private static final long RAW_CONTACT_ID = 11;
+ private static final long DATA_ID = 21;
+ private static final String LOOKUP_KEY = "aa%12%@!";
+
+ private ContactsMockContext mMockContext;
+ private MockContentProvider mContactsProvider;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mMockContext = new ContactsMockContext(getContext());
+ mContactsProvider = mMockContext.getContactsProvider();
+
+ InjectedServices services = new InjectedServices();
+ AccountType accountType = new BaseAccountType() {
+ @Override
+ public boolean areContactsWritable() {
+ return false;
+ }
+ };
+ accountType.accountType = "mockAccountType";
+
+ AccountWithDataSet account =
+ new AccountWithDataSet("mockAccountName", "mockAccountType", null);
+
+ AccountTypeManager.setInstanceForTest(
+ new MockAccountTypeManager(
+ new AccountType[]{accountType}, new AccountWithDataSet[]{account}));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mMockContext = null;
+ mContactsProvider = null;
+ super.tearDown();
+ }
+
+ private Contact assertLoadContact(Uri uri) {
+ final ContactLoader loader = new ContactLoader(mMockContext, uri, true);
+ return getLoaderResultSynchronously(loader);
+ }
+
+ public void testNullUri() {
+ Contact result = assertLoadContact(null);
+ assertTrue(result.isError());
+ }
+
+ public void testEmptyUri() {
+ Contact result = assertLoadContact(Uri.EMPTY);
+ assertTrue(result.isError());
+ }
+
+ public void testInvalidUri() {
+ Contact result = assertLoadContact(Uri.parse("content://wtf"));
+ assertTrue(result.isError());
+ }
+
+ public void testLoadContactWithContactIdUri() {
+ // Use content Uris that only contain the ID
+ final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, CONTACT_ID);
+ final Uri entityUri = Uri.withAppendedPath(baseUri, Contacts.Entity.CONTENT_DIRECTORY);
+ final Uri lookupUri = ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, LOOKUP_KEY),
+ CONTACT_ID);
+
+ ContactQueries queries = new ContactQueries();
+ mContactsProvider.expectTypeQuery(baseUri, Contacts.CONTENT_ITEM_TYPE);
+ queries.fetchAllData(entityUri, CONTACT_ID, RAW_CONTACT_ID, DATA_ID, LOOKUP_KEY);
+
+ Contact contact = assertLoadContact(baseUri);
+
+ assertEquals(CONTACT_ID, contact.getId());
+ assertEquals(RAW_CONTACT_ID, contact.getNameRawContactId());
+ assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
+ assertEquals(LOOKUP_KEY, contact.getLookupKey());
+ assertEquals(lookupUri, contact.getLookupUri());
+ assertEquals(1, contact.getRawContacts().size());
+ assertEquals(1, contact.getStatuses().size());
+ mContactsProvider.verify();
+ }
+
+ public void testLoadContactWithOldStyleUri() {
+ // Use content Uris that only contain the ID but use the format used in Donut
+ final Uri legacyUri = ContentUris.withAppendedId(
+ Uri.parse("content://contacts"), RAW_CONTACT_ID);
+ final Uri rawContactUri = ContentUris.withAppendedId(
+ RawContacts.CONTENT_URI, RAW_CONTACT_ID);
+ final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, CONTACT_ID);
+ final Uri lookupUri = ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, LOOKUP_KEY),
+ CONTACT_ID);
+ final Uri entityUri = Uri.withAppendedPath(lookupUri, Contacts.Entity.CONTENT_DIRECTORY);
+
+ ContactQueries queries = new ContactQueries();
+ queries.fetchContactIdAndLookupFromRawContactUri(rawContactUri, CONTACT_ID, LOOKUP_KEY);
+ queries.fetchAllData(entityUri, CONTACT_ID, RAW_CONTACT_ID, DATA_ID, LOOKUP_KEY);
+
+ Contact contact = assertLoadContact(legacyUri);
+
+ assertEquals(CONTACT_ID, contact.getId());
+ assertEquals(RAW_CONTACT_ID, contact.getNameRawContactId());
+ assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
+ assertEquals(LOOKUP_KEY, contact.getLookupKey());
+ assertEquals(lookupUri, contact.getLookupUri());
+ assertEquals(1, contact.getRawContacts().size());
+ assertEquals(1, contact.getStatuses().size());
+ if (CompatUtils.isMarshmallowCompatible()) {
+ assertEquals(
+ 1, contact.getRawContacts().get(0).getDataItems().get(0).getCarrierPresence());
+ }
+ mContactsProvider.verify();
+ }
+
+ public void testLoadContactWithRawContactIdUri() {
+ // Use content Uris that only contain the ID but use the format used in Donut
+ final Uri rawContactUri = ContentUris.withAppendedId(
+ RawContacts.CONTENT_URI, RAW_CONTACT_ID);
+ final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, CONTACT_ID);
+ final Uri lookupUri = ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, LOOKUP_KEY),
+ CONTACT_ID);
+ final Uri entityUri = Uri.withAppendedPath(lookupUri, Contacts.Entity.CONTENT_DIRECTORY);
+
+ ContactQueries queries = new ContactQueries();
+ mContactsProvider.expectTypeQuery(rawContactUri, RawContacts.CONTENT_ITEM_TYPE);
+ queries.fetchContactIdAndLookupFromRawContactUri(rawContactUri, CONTACT_ID, LOOKUP_KEY);
+ queries.fetchAllData(entityUri, CONTACT_ID, RAW_CONTACT_ID, DATA_ID, LOOKUP_KEY);
+
+ Contact contact = assertLoadContact(rawContactUri);
+
+ assertEquals(CONTACT_ID, contact.getId());
+ assertEquals(RAW_CONTACT_ID, contact.getNameRawContactId());
+ assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
+ assertEquals(LOOKUP_KEY, contact.getLookupKey());
+ assertEquals(lookupUri, contact.getLookupUri());
+ assertEquals(1, contact.getRawContacts().size());
+ assertEquals(1, contact.getStatuses().size());
+ mContactsProvider.verify();
+ }
+
+ public void testLoadContactWithContactLookupUri() {
+ // Use lookup-style Uris that do not contain the Contact-ID
+ final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, CONTACT_ID);
+ final Uri lookupNoIdUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, LOOKUP_KEY);
+ final Uri lookupUri = ContentUris.withAppendedId(lookupNoIdUri, CONTACT_ID);
+ final Uri entityUri = Uri.withAppendedPath(
+ lookupNoIdUri, Contacts.Entity.CONTENT_DIRECTORY);
+
+ ContactQueries queries = new ContactQueries();
+ mContactsProvider.expectTypeQuery(lookupNoIdUri, Contacts.CONTENT_ITEM_TYPE);
+ queries.fetchAllData(entityUri, CONTACT_ID, RAW_CONTACT_ID, DATA_ID, LOOKUP_KEY);
+
+ Contact contact = assertLoadContact(lookupNoIdUri);
+
+ assertEquals(CONTACT_ID, contact.getId());
+ assertEquals(RAW_CONTACT_ID, contact.getNameRawContactId());
+ assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
+ assertEquals(LOOKUP_KEY, contact.getLookupKey());
+ assertEquals(lookupUri, contact.getLookupUri());
+ assertEquals(1, contact.getRawContacts().size());
+ assertEquals(1, contact.getStatuses().size());
+ mContactsProvider.verify();
+ }
+
+ public void testLoadContactWithContactLookupAndIdUri() {
+ // Use lookup-style Uris that also contain the Contact-ID
+ final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, CONTACT_ID);
+ final Uri lookupUri = ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, LOOKUP_KEY),
+ CONTACT_ID);
+ final Uri entityUri = Uri.withAppendedPath(lookupUri, Contacts.Entity.CONTENT_DIRECTORY);
+
+ ContactQueries queries = new ContactQueries();
+ mContactsProvider.expectTypeQuery(lookupUri, Contacts.CONTENT_ITEM_TYPE);
+ queries.fetchAllData(entityUri, CONTACT_ID, RAW_CONTACT_ID, DATA_ID, LOOKUP_KEY);
+
+ Contact contact = assertLoadContact(lookupUri);
+
+ assertEquals(CONTACT_ID, contact.getId());
+ assertEquals(RAW_CONTACT_ID, contact.getNameRawContactId());
+ assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
+ assertEquals(LOOKUP_KEY, contact.getLookupKey());
+ assertEquals(lookupUri, contact.getLookupUri());
+ assertEquals(1, contact.getRawContacts().size());
+ assertEquals(1, contact.getStatuses().size());
+ mContactsProvider.verify();
+ }
+
+ public void testLoadContactWithContactLookupWithIncorrectIdUri() {
+ // Use lookup-style Uris that contain incorrect Contact-ID
+ // (we want to ensure that still the correct contact is chosen)
+ final long wrongContactId = 2;
+ final long wrongRawContactId = 12;
+
+ final String wrongLookupKey = "ab%12%@!";
+ final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, CONTACT_ID);
+ final Uri wrongBaseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, wrongContactId);
+ final Uri lookupUri = ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, LOOKUP_KEY),
+ CONTACT_ID);
+ final Uri lookupWithWrongIdUri = ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, LOOKUP_KEY),
+ wrongContactId);
+ final Uri entityUri = Uri.withAppendedPath(lookupWithWrongIdUri,
+ Contacts.Entity.CONTENT_DIRECTORY);
+
+ ContactQueries queries = new ContactQueries();
+ mContactsProvider.expectTypeQuery(lookupWithWrongIdUri, Contacts.CONTENT_ITEM_TYPE);
+ queries.fetchAllData(entityUri, CONTACT_ID, RAW_CONTACT_ID, DATA_ID, LOOKUP_KEY);
+
+ Contact contact = assertLoadContact(lookupWithWrongIdUri);
+
+ assertEquals(CONTACT_ID, contact.getId());
+ assertEquals(RAW_CONTACT_ID, contact.getNameRawContactId());
+ assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
+ assertEquals(LOOKUP_KEY, contact.getLookupKey());
+ assertEquals(lookupUri, contact.getLookupUri());
+ assertEquals(1, contact.getRawContacts().size());
+ assertEquals(1, contact.getStatuses().size());
+
+ mContactsProvider.verify();
+ }
+
+ public void testLoadContactReturnDirectoryContactWithoutDisplayName() throws JSONException {
+ // Use lookup-style Uri that contains encoded json object which encapsulates the
+ // directory contact. The test json object is:
+ // {
+ // display_name_source": 40,
+ // "vnd.android.cursor.item\/contact":{"email":{"data1":"test@google.com" }}
+ // }
+ JSONObject itemJson = new JSONObject();
+ itemJson.put("email", new JSONObject().put("data1", "test@google.com"));
+ JSONObject json = new JSONObject();
+ json.put(Contacts.NAME_RAW_CONTACT_ID, CONTACT_ID);
+ json.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME);
+ json.put(Contacts.CONTENT_ITEM_TYPE, itemJson);
+
+ final Uri lookupUri = Contacts.CONTENT_LOOKUP_URI.buildUpon()
+ .encodedFragment(json.toString())
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, "1")
+ .appendPath(Constants.LOOKUP_URI_ENCODED).build();
+
+ mContactsProvider.expectTypeQuery(lookupUri, Contacts.CONTENT_ITEM_TYPE);
+ Contact contact = assertLoadContact(lookupUri);
+
+ assertEquals(-1, contact.getId());
+ assertEquals(-1, contact.getNameRawContactId());
+ assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
+ assertEquals("", contact.getDisplayName());
+ assertEquals(lookupUri, contact.getLookupUri());
+ assertEquals(1, contact.getRawContacts().size());
+ mContactsProvider.verify();
+ }
+
+ class ContactQueries {
+ public void fetchAllData(
+ Uri baseUri, long contactId, long rawContactId, long dataId, String encodedLookup) {
+ final String[] COLUMNS_INTERNAL = new String[] {
+ Contacts.NAME_RAW_CONTACT_ID, Contacts.DISPLAY_NAME_SOURCE,
+ Contacts.LOOKUP_KEY, Contacts.DISPLAY_NAME,
+ Contacts.DISPLAY_NAME_ALTERNATIVE, Contacts.PHONETIC_NAME,
+ Contacts.PHOTO_ID, Contacts.STARRED, Contacts.CONTACT_PRESENCE,
+ Contacts.CONTACT_STATUS, Contacts.CONTACT_STATUS_TIMESTAMP,
+ Contacts.CONTACT_STATUS_RES_PACKAGE, Contacts.CONTACT_STATUS_LABEL,
+
+ Contacts.Entity.CONTACT_ID,
+ Contacts.Entity.RAW_CONTACT_ID,
+
+ RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_TYPE,
+ RawContacts.DATA_SET,
+ RawContacts.DIRTY, RawContacts.VERSION, RawContacts.SOURCE_ID,
+ RawContacts.SYNC1, RawContacts.SYNC2, RawContacts.SYNC3, RawContacts.SYNC4,
+ RawContacts.DELETED,
+
+ Contacts.Entity.DATA_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,
+ Data.SYNC1, Data.SYNC2, Data.SYNC3, Data.SYNC4,
+ Data.DATA_VERSION, Data.IS_PRIMARY,
+ Data.IS_SUPER_PRIMARY, Data.MIMETYPE,
+
+ GroupMembership.GROUP_SOURCE_ID,
+
+ Data.PRESENCE, Data.CHAT_CAPABILITY,
+ Data.STATUS, Data.STATUS_RES_PACKAGE, Data.STATUS_ICON,
+ Data.STATUS_LABEL, Data.STATUS_TIMESTAMP,
+
+ Contacts.PHOTO_URI,
+
+ Contacts.SEND_TO_VOICEMAIL,
+ Contacts.CUSTOM_RINGTONE,
+ Contacts.IS_USER_PROFILE,
+
+ Data.TIMES_USED,
+ Data.LAST_TIME_USED
+ };
+
+ List<String> projectionList = Lists.newArrayList(COLUMNS_INTERNAL);
+ if (CompatUtils.isMarshmallowCompatible()) {
+ projectionList.add(Data.CARRIER_PRESENCE);
+ }
+ final String[] COLUMNS = projectionList.toArray(new String[projectionList.size()]);
+
+ final Object[] ROWS_INTERNAL = new Object[] {
+ rawContactId, 40,
+ "aa%12%@!", "John Doe", "Doe, John", "jdo",
+ 0, 0, StatusUpdates.AVAILABLE,
+ "Having lunch", 0,
+ "mockPkg1", 10,
+
+ contactId,
+ rawContactId,
+
+ "mockAccountName", "mockAccountType", null,
+ 0, 1, 0,
+ "sync1", "sync2", "sync3", "sync4",
+ 0,
+
+ dataId,
+
+ "dat1", "dat2", "dat3", "dat4", "dat5",
+ "dat6", "dat7", "dat8", "dat9", "dat10",
+ "dat11", "dat12", "dat13", "dat14", "dat15",
+ "syn1", "syn2", "syn3", "syn4",
+
+ 0, 0,
+ 0, StructuredName.CONTENT_ITEM_TYPE,
+
+ "groupId",
+
+ StatusUpdates.INVISIBLE, null,
+ "Having dinner", "mockPkg3", 0,
+ 20, 0,
+
+ "content:some.photo.uri",
+
+ 0,
+ null,
+ 0,
+
+ 0,
+ 0
+ };
+
+ List<Object> rowsList = Lists.newArrayList(ROWS_INTERNAL);
+ if (CompatUtils.isMarshmallowCompatible()) {
+ rowsList.add(Data.CARRIER_PRESENCE_VT_CAPABLE);
+ }
+ final Object[] ROWS = rowsList.toArray(new Object[rowsList.size()]);
+
+ mContactsProvider.expectQuery(baseUri)
+ .withProjection(COLUMNS)
+ .withSortOrder(Contacts.Entity.RAW_CONTACT_ID)
+ .returnRow(ROWS);
+ }
+
+ void fetchLookupAndId(final Uri sourceUri, final long expectedContactId,
+ final String expectedEncodedLookup) {
+ mContactsProvider.expectQuery(sourceUri)
+ .withProjection(Contacts.LOOKUP_KEY, Contacts._ID)
+ .returnRow(expectedEncodedLookup, expectedContactId);
+ }
+
+ void fetchContactIdAndLookupFromRawContactUri(final Uri rawContactUri,
+ final long expectedContactId, final String expectedEncodedLookup) {
+ // TODO: use a lighter query by joining rawcontacts with contacts in provider
+ // (See ContactContracts.java)
+ final Uri dataUri = Uri.withAppendedPath(rawContactUri,
+ RawContacts.Data.CONTENT_DIRECTORY);
+ mContactsProvider.expectQuery(dataUri)
+ .withProjection(RawContacts.CONTACT_ID, Contacts.LOOKUP_KEY)
+ .returnRow(expectedContactId, expectedEncodedLookup);
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/common/model/RawContactTest.java b/tests/src/com/android/contacts/common/model/RawContactTest.java
new file mode 100644
index 0000000..b8e03c3
--- /dev/null
+++ b/tests/src/com/android/contacts/common/model/RawContactTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2012 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.common.model;
+
+import android.content.ContentValues;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.contacts.common.model.RawContact;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link RawContact}.
+ */
+public class RawContactTest extends TestCase {
+
+ private RawContact buildRawContact() {
+ final ContentValues values = new ContentValues();
+ values.put("key1", "value1");
+ values.put("key2", "value2");
+
+ final ContentValues dataItem = new ContentValues();
+ dataItem.put("key3", "value3");
+ dataItem.put("key4", "value4");
+
+ final RawContact contact = new RawContact(values);
+ contact.addDataItemValues(dataItem);
+
+ return contact;
+ }
+
+ private RawContact buildRawContact2() {
+ final ContentValues values = new ContentValues();
+ values.put("key11", "value11");
+ values.put("key22", "value22");
+
+ final ContentValues dataItem = new ContentValues();
+ dataItem.put("key33", "value33");
+ dataItem.put("key44", "value44");
+
+ final RawContact contact = new RawContact(values);
+ contact.addDataItemValues(dataItem);
+
+ return contact;
+ }
+
+ public void testNotEquals() {
+ final RawContact one = buildRawContact();
+ final RawContact two = buildRawContact2();
+ assertFalse(one.equals(two));
+ }
+
+ public void testEquals() {
+ assertEquals(buildRawContact(), buildRawContact());
+ }
+
+ public void testParcelable() {
+ assertParcelableEquals(buildRawContact());
+ }
+
+ private RawContact.NamedDataItem buildNamedDataItem() {
+ final ContentValues values = new ContentValues();
+ values.put("key1", "value1");
+ values.put("key2", "value2");
+ final Uri uri = Uri.fromParts("content:", "ssp", "fragment");
+
+ return new RawContact.NamedDataItem(uri, values);
+ }
+
+ private RawContact.NamedDataItem buildNamedDataItem2() {
+ final ContentValues values = new ContentValues();
+ values.put("key11", "value11");
+ values.put("key22", "value22");
+ final Uri uri = Uri.fromParts("content:", "blah", "blah");
+
+ return new RawContact.NamedDataItem(uri, values);
+ }
+
+ public void testNamedDataItemEquals() {
+ assertEquals(buildNamedDataItem(), buildNamedDataItem());
+ }
+
+ public void testNamedDataItemNotEquals() {
+ assertFalse(buildNamedDataItem().equals(buildNamedDataItem2()));
+ }
+
+ public void testNamedDataItemParcelable() {
+ assertParcelableEquals(buildNamedDataItem());
+ }
+
+ private void assertParcelableEquals(Parcelable parcelable) {
+ final Parcel parcel = Parcel.obtain();
+ try {
+ parcel.writeParcelable(parcelable, 0);
+ parcel.setDataPosition(0);
+
+ Parcelable out = parcel.readParcelable(parcelable.getClass().getClassLoader());
+ assertEquals(parcelable, out);
+ } finally {
+ parcel.recycle();
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/common/model/ValuesDeltaTests.java b/tests/src/com/android/contacts/common/model/ValuesDeltaTests.java
new file mode 100644
index 0000000..77bf456
--- /dev/null
+++ b/tests/src/com/android/contacts/common/model/ValuesDeltaTests.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 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.common.model;
+
+import android.content.ContentProviderOperation.Builder;
+import android.content.ContentValues;
+import android.os.Build;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Data;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.contacts.common.compat.CompatUtils;
+import com.android.contacts.common.model.BuilderWrapper;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link ValuesDelta}. These tests
+ * focus on passing changes across {@link android.os.Parcel}, and verifying that they
+ * correctly build expected "diff" operations.
+ */
+@SmallTest
+public class ValuesDeltaTests extends TestCase {
+
+ 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 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 BuilderWrapper builderWrapper = values.buildDiffWrapper(Data.CONTENT_URI);
+ final boolean isInsert = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ ? builderWrapper.getBuilder().build().isInsert()
+ : builderWrapper.getType() == CompatUtils.TYPE_INSERT;
+ assertTrue("Didn't produce insert action", isInsert);
+ }
+
+ /**
+ * 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 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 BuilderWrapper builderWrapper = values.buildDiffWrapper(Data.CONTENT_URI);
+ final boolean isUpdate = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+ ? builderWrapper.getBuilder().build().isUpdate()
+ : builderWrapper.getType() == CompatUtils.TYPE_UPDATE;
+ assertTrue("Didn't produce update action", isUpdate);
+ }
+}
diff --git a/tests/src/com/android/contacts/common/model/account/AccountTypeTest.java b/tests/src/com/android/contacts/common/model/account/AccountTypeTest.java
new file mode 100644
index 0000000..e204722
--- /dev/null
+++ b/tests/src/com/android/contacts/common/model/account/AccountTypeTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2011 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.common.model.account;
+
+import android.content.Context;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.contacts.common.tests.R;
+
+/**
+ * Test case for {@link AccountType}.
+ *
+ * adb shell am instrument -w -e class com.android.contacts.model.AccountTypeTest \
+ com.android.contacts.tests/android.test.InstrumentationTestRunner
+ */
+@SmallTest
+public class AccountTypeTest extends InstrumentationTestCase {
+ public void testGetResourceText() {
+ // In this test we use the test package itself as an external package.
+ final String packageName = getInstrumentation().getContext().getPackageName();
+
+ final Context c = getInstrumentation().getTargetContext();
+ final String DEFAULT = "ABC";
+
+ // Package name null, resId -1, use the default
+ assertEquals(DEFAULT, AccountType.getResourceText(c, null, -1, DEFAULT));
+
+ // Resource ID -1, use the default
+ assertEquals(DEFAULT, AccountType.getResourceText(c, packageName, -1, DEFAULT));
+
+ // Load from an external package. (here, we use this test package itself)
+ final int externalResID = R.string.test_string;
+ assertEquals(getInstrumentation().getContext().getString(externalResID),
+ AccountType.getResourceText(c, packageName, externalResID, DEFAULT));
+
+ // Load from the contacts package itself.
+ final int internalResId = com.android.contacts.common.R.string.contactsList;
+ assertEquals(c.getString(internalResId),
+ AccountType.getResourceText(c, null, internalResId, DEFAULT));
+ }
+
+ /**
+ * Verify if {@link AccountType#getInviteContactActionLabel} correctly gets the resource ID
+ * from {@link AccountType#getInviteContactActionResId}
+ */
+ public void testGetInviteContactActionLabel() {
+ final String packageName = getInstrumentation().getContext().getPackageName();
+ final Context c = getInstrumentation().getTargetContext();
+
+ final int externalResID = R.string.test_string;
+
+ AccountType accountType = new AccountType() {
+ {
+ resourcePackageName = packageName;
+ syncAdapterPackageName = packageName;
+ }
+ @Override protected int getInviteContactActionResId() {
+ return externalResID;
+ }
+
+ @Override public boolean isGroupMembershipEditable() {
+ return false;
+ }
+
+ @Override public boolean areContactsWritable() {
+ return false;
+ }
+ };
+
+ assertEquals(getInstrumentation().getContext().getString(externalResID),
+ accountType.getInviteContactActionLabel(c));
+ }
+
+ public void testDisplayLabelComparator() {
+ final AccountTypeForDisplayLabelTest EMPTY = new AccountTypeForDisplayLabelTest("");
+ final AccountTypeForDisplayLabelTest NULL = new AccountTypeForDisplayLabelTest(null);
+ final AccountTypeForDisplayLabelTest AA = new AccountTypeForDisplayLabelTest("aa");
+ final AccountTypeForDisplayLabelTest BBB = new AccountTypeForDisplayLabelTest("bbb");
+ final AccountTypeForDisplayLabelTest C = new AccountTypeForDisplayLabelTest("c");
+
+ assertTrue(compareDisplayLabel(AA, BBB) < 0);
+ assertTrue(compareDisplayLabel(BBB, C) < 0);
+ assertTrue(compareDisplayLabel(AA, C) < 0);
+ assertTrue(compareDisplayLabel(AA, AA) == 0);
+ assertTrue(compareDisplayLabel(BBB, AA) > 0);
+
+ assertTrue(compareDisplayLabel(EMPTY, AA) < 0);
+ assertTrue(compareDisplayLabel(EMPTY, NULL) == 0);
+ }
+
+ private int compareDisplayLabel(AccountType lhs, AccountType rhs) {
+ return new AccountType.DisplayLabelComparator(
+ getInstrumentation().getTargetContext()).compare(lhs, rhs);
+ }
+
+ private class AccountTypeForDisplayLabelTest extends AccountType {
+ private final String mDisplayLabel;
+
+ public AccountTypeForDisplayLabelTest(String displayLabel) {
+ mDisplayLabel = displayLabel;
+ }
+
+ @Override
+ public CharSequence getDisplayLabel(Context context) {
+ return mDisplayLabel;
+ }
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return false;
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return false;
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/common/model/account/ExternalAccountTypeTest.java b/tests/src/com/android/contacts/common/model/account/ExternalAccountTypeTest.java
new file mode 100644
index 0000000..50a5110
--- /dev/null
+++ b/tests/src/com/android/contacts/common/model/account/ExternalAccountTypeTest.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2011 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.common.model.account;
+
+import android.content.Context;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.provider.ContactsContract.CommonDataKinds.Note;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.Relation;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.tests.R;
+import com.google.common.base.Objects;
+
+import java.util.List;
+
+/**
+ * Test case for {@link com.android.contacts.common.model.account.ExternalAccountType}.
+ *
+ * adb shell am instrument -w -e class com.android.contacts.model.ExternalAccountTypeTest \
+ com.android.contacts.tests/android.test.InstrumentationTestRunner
+ */
+@SmallTest
+public class ExternalAccountTypeTest extends InstrumentationTestCase {
+
+ @Suppress
+ public void testResolveExternalResId() {
+ final Context c = getInstrumentation().getTargetContext();
+ // In this test we use the test package itself as an external package.
+ final String packageName = getInstrumentation().getContext().getPackageName();
+
+ // Resource name empty.
+ assertEquals(-1, ExternalAccountType.resolveExternalResId(c, null, packageName, ""));
+ assertEquals(-1, ExternalAccountType.resolveExternalResId(c, "", packageName, ""));
+
+ // Name doesn't begin with '@'
+ assertEquals(-1, ExternalAccountType.resolveExternalResId(c, "x", packageName, ""));
+
+ // Invalid resource name
+ assertEquals(-1, ExternalAccountType.resolveExternalResId(c, "@", packageName, ""));
+ assertEquals(-1, ExternalAccountType.resolveExternalResId(c, "@a", packageName, ""));
+ assertEquals(-1, ExternalAccountType.resolveExternalResId(c, "@a/b", packageName, ""));
+
+ // Valid resource name
+ assertEquals(R.string.test_string, ExternalAccountType.resolveExternalResId(c,
+ "@string/test_string", packageName, ""));
+ }
+
+ /**
+ * Initialize with an invalid package name and see if type will be initialized, but empty.
+ */
+ public void testNoPackage() {
+ final ExternalAccountType type = new ExternalAccountType(getInstrumentation().getTargetContext(),
+ "!!!no such package name!!!", false);
+ assertTrue(type.isInitialized());
+ }
+
+ /**
+ * Initialize with the test package itself and see if EditSchema is correctly parsed.
+ */
+ @Suppress
+ public void testEditSchema() {
+ final ExternalAccountType type = new ExternalAccountType(getInstrumentation().getTargetContext(),
+ getInstrumentation().getContext().getPackageName(), false);
+
+ assertTrue(type.isInitialized());
+
+ // Let's just check if the DataKinds are registered.
+ assertNotNull(type.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME));
+ assertNotNull(type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME));
+ assertNotNull(type.getKindForMimetype(Email.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(Im.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(Organization.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(Note.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(Website.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(SipAddress.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(Event.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(Relation.CONTENT_ITEM_TYPE));
+ }
+
+ /**
+ * Initialize with "contacts_fallback.xml" and compare the DataKinds to those of
+ * {@link com.android.contacts.common.model.account.FallbackAccountType}.
+ */
+ public void testEditSchema_fallback() {
+ final ExternalAccountType type = new ExternalAccountType(getInstrumentation().getTargetContext(),
+ getInstrumentation().getContext().getPackageName(), false,
+ getInstrumentation().getContext().getResources().getXml(R.xml.contacts_fallback)
+ );
+
+ assertTrue(type.isInitialized());
+
+ // Create a fallback type with the same resource package name, and compare all the data
+ // kinds to its.
+ final AccountType reference = FallbackAccountType.createWithPackageNameForTest(
+ getInstrumentation().getTargetContext(), type.resourcePackageName);
+
+ assertsDataKindEquals(reference.getSortedDataKinds(), type.getSortedDataKinds());
+ }
+
+ public void testEditSchema_mustHaveChecks() {
+ checkEditSchema_mustHaveChecks(R.xml.missing_contacts_base, true);
+ checkEditSchema_mustHaveChecks(R.xml.missing_contacts_photo, false);
+ checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name, false);
+ checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr1, false);
+ checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr2, false);
+ checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr3, false);
+ checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr4, false);
+ checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr5, false);
+ checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr6, false);
+ checkEditSchema_mustHaveChecks(R.xml.missing_contacts_name_attr7, false);
+ }
+
+ private void checkEditSchema_mustHaveChecks(int xmlResId, boolean expectInitialized) {
+ final ExternalAccountType type = new ExternalAccountType(getInstrumentation().getTargetContext(),
+ getInstrumentation().getContext().getPackageName(), false,
+ getInstrumentation().getContext().getResources().getXml(xmlResId)
+ );
+
+ assertEquals(expectInitialized, type.isInitialized());
+ }
+
+ /**
+ * Initialize with "contacts_readonly.xml" and see if all data kinds are correctly registered.
+ */
+ public void testReadOnlyDefinition() {
+ final ExternalAccountType type = new ExternalAccountType(getInstrumentation().getTargetContext(),
+ getInstrumentation().getContext().getPackageName(), false,
+ getInstrumentation().getContext().getResources().getXml(R.xml.contacts_readonly)
+ );
+ assertTrue(type.isInitialized());
+
+ // Shouldn't have a "null" mimetype.
+ assertTrue(type.getKindForMimetype(null) == null);
+
+ // 3 kinds are defined in XML and 4 are added by default.
+ assertEquals(4 + 3, type.getSortedDataKinds().size());
+
+ // Check for the default kinds.
+ assertNotNull(type.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE));
+ assertNotNull(type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME));
+ assertNotNull(type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME));
+ assertNotNull(type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE));
+
+ // Check for type specific kinds.
+ DataKind kind = type.getKindForMimetype("vnd.android.cursor.item/a.b.c");
+ assertNotNull(kind);
+ // No check for icon -- we actually just ignore it.
+ assertEquals("data1", ((BaseAccountType.SimpleInflater) kind.actionHeader)
+ .getColumnNameForTest());
+ assertEquals("data2", ((BaseAccountType.SimpleInflater) kind.actionBody)
+ .getColumnNameForTest());
+
+ kind = type.getKindForMimetype("vnd.android.cursor.item/d.e.f");
+ assertNotNull(kind);
+ assertEquals("data3", ((BaseAccountType.SimpleInflater) kind.actionHeader)
+ .getColumnNameForTest());
+ assertEquals("data4", ((BaseAccountType.SimpleInflater) kind.actionBody)
+ .getColumnNameForTest());
+
+ kind = type.getKindForMimetype("vnd.android.cursor.item/xyz");
+ assertNotNull(kind);
+ assertEquals("data5", ((BaseAccountType.SimpleInflater) kind.actionHeader)
+ .getColumnNameForTest());
+ assertEquals("data6", ((BaseAccountType.SimpleInflater) kind.actionBody)
+ .getColumnNameForTest());
+ }
+
+ private static void assertsDataKindEquals(List<DataKind> expectedKinds,
+ List<DataKind> actualKinds) {
+ final int count = Math.max(actualKinds.size(), expectedKinds.size());
+ for (int i = 0; i < count; i++) {
+ String actual = actualKinds.size() > i ? actualKinds.get(i).toString() : "(n/a)";
+ String expected = expectedKinds.size() > i ? expectedKinds.get(i).toString() : "(n/a)";
+
+ // Because assertEquals()'s output is not very friendly when comparing two similar
+ // strings, we manually do the check.
+ if (!Objects.equal(actual, expected)) {
+ final int commonPrefixEnd = findCommonPrefixEnd(actual, expected);
+ fail("Kind #" + i
+ + "\n[Actual]\n" + insertMarkerAt(actual, commonPrefixEnd)
+ + "\n[Expected]\n" + insertMarkerAt(expected, commonPrefixEnd));
+ }
+ }
+ }
+
+ private static int findCommonPrefixEnd(String s1, String s2) {
+ int i = 0;
+ for (;;) {
+ final boolean s1End = (s1.length() <= i);
+ final boolean s2End = (s2.length() <= i);
+ if (s1End || s2End) {
+ return i;
+ }
+ if (s1.charAt(i) != s2.charAt(i)) {
+ return i;
+ }
+ i++;
+ }
+ }
+
+ private static String insertMarkerAt(String s, int position) {
+ final String MARKER = "***";
+ if (position > s.length()) {
+ return s + MARKER;
+ } else {
+ return new StringBuilder(s).insert(position, MARKER).toString();
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/common/model/dataitem/DataItemTests.java b/tests/src/com/android/contacts/common/model/dataitem/DataItemTests.java
new file mode 100644
index 0000000..ec1a8da
--- /dev/null
+++ b/tests/src/com/android/contacts/common/model/dataitem/DataItemTests.java
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2014 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.common.model.dataitem;
+
+import android.content.ContentValues;
+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.Relation;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
+import android.provider.ContactsContract.Contacts.Data;
+import android.provider.ContactsContract.Contacts.Entity;
+import android.test.AndroidTestCase;
+
+import com.android.contacts.common.Collapser;
+import com.android.contacts.common.model.account.AccountType.EditType;
+import com.android.contacts.common.model.account.BaseAccountType;
+import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.model.dataitem.DataItem;
+import com.android.contacts.common.model.dataitem.DataKind;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test case for {@link DataItem}.
+ */
+public class DataItemTests extends AndroidTestCase {
+
+ private ContentValues mValues1;
+ private ContentValues mValues2;
+ private ContentValues mValues3;
+ private ContentValues mValues4;
+ private GoogleAccountType mGoogleAccountType;
+
+ @Override
+ protected void setUp() {
+ mValues1 = new ContentValues();
+ mValues2 = new ContentValues();
+ mValues3 = new ContentValues();
+ mValues4 = new ContentValues();
+
+ mValues1.put(Data._ID, 1);
+ mValues2.put(Data._ID, 2);
+ mValues3.put(Data._ID, 3);
+ mValues4.put(Data._ID, 4);
+
+ mGoogleAccountType = new GoogleAccountType(getContext(), "packageName");
+ }
+
+ private List<DataItem> createDataItemsAndCollapse(DataKind kind, ContentValues... values) {
+ final List<DataItem> dataList = new ArrayList<>(values.length);
+ for (ContentValues value : values) {
+ final DataItem data = DataItem.createFrom(value);
+ data.setDataKind(kind);
+ dataList.add(data);
+ }
+ Collapser.collapseList(dataList, getContext());
+ return dataList;
+ }
+
+ public void testDataItemCollapsing_genericDataItemFields() {
+ mValues1.put(Data.IS_SUPER_PRIMARY, 1);
+ mValues2.put(Data.IS_PRIMARY, 0);
+
+ mValues1.put(Entity.TIMES_USED, 5);
+ mValues2.put(Entity.TIMES_USED, 4);
+
+ mValues1.put(Entity.LAST_TIME_USED, 555);
+ mValues2.put(Entity.LAST_TIME_USED, 999);
+
+ final DataKind kind = new DataKind("test.mimetype", 0, 0, false);
+ kind.actionBody = new BaseAccountType.SimpleInflater(0);
+ kind.typeList = new ArrayList<>();
+ kind.typeList.add(new EditType(1, -1));
+ kind.typeList.add(new EditType(2, -1));
+ kind.typeColumn = Data.DATA2;
+
+ mValues1.put(kind.typeColumn, 2);
+ mValues2.put(kind.typeColumn, 1);
+
+ final List<DataItem> dataList = createDataItemsAndCollapse(kind, mValues1, mValues2);
+
+ assertEquals(1, dataList.size());
+ assertEquals(true, dataList.get(0).isSuperPrimary());
+ assertEquals(true, dataList.get(0).isPrimary());
+ assertEquals(9, (int) dataList.get(0).getTimesUsed());
+ assertEquals(999L, (long) dataList.get(0).getLastTimeUsed());
+ assertEquals(1, dataList.get(0).getKindTypeColumn(kind));
+ }
+
+ public void testDataItemCollapsing_email() {
+ final String email1 = "email1@google.com";
+ final String email2 = "email2@google.com";
+
+ mValues1.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+
+ mValues1.put(Email.ADDRESS, email1);
+ mValues2.put(Email.ADDRESS, email1);
+ mValues3.put(Email.ADDRESS, email2);
+
+ mValues1.put(Email.TYPE, Email.TYPE_MOBILE);
+ mValues2.put(Email.TYPE, Email.TYPE_HOME);
+ mValues3.put(Email.TYPE, Email.TYPE_WORK);
+
+ final DataKind kind = mGoogleAccountType.getKindForMimetype(Email.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3);
+
+ assertEquals(2, dataList.size());
+ assertEquals(email1, ((EmailDataItem) dataList.get(0)).getAddress());
+ assertEquals(email2, ((EmailDataItem) dataList.get(1)).getAddress());
+ assertEquals(Math.min(Email.TYPE_MOBILE, Email.TYPE_HOME),
+ ((EmailDataItem) dataList.get(0)).getKindTypeColumn(kind));
+ }
+
+ public void testDataItemCollapsing_event() {
+ final String date1 = "2014-01-01";
+ final String date2 = "2014-02-02";
+ final String customLabel1 = "custom label1";
+ final String customLabel2 = "custom label2";
+
+ mValues1.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
+ mValues4.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
+
+ mValues1.put(Event.START_DATE, date1);
+ mValues2.put(Event.START_DATE, date1);
+ mValues3.put(Event.START_DATE, date1);
+ mValues4.put(Event.START_DATE, date2);
+
+ mValues1.put(Event.TYPE, Event.TYPE_CUSTOM);
+ mValues2.put(Event.TYPE, Event.TYPE_CUSTOM);
+ mValues3.put(Event.TYPE, Event.TYPE_CUSTOM);
+ mValues4.put(Event.TYPE, Event.TYPE_ANNIVERSARY);
+
+ mValues1.put(Event.LABEL, customLabel1);
+ mValues2.put(Event.LABEL, customLabel1);
+ mValues3.put(Event.LABEL, customLabel2);
+
+ final DataKind kind = mGoogleAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3, mValues4);
+
+ assertEquals(3, dataList.size());
+ assertEquals(customLabel1, ((EventDataItem) dataList.get(0)).getLabel());
+ assertEquals(customLabel2, ((EventDataItem) dataList.get(1)).getLabel());
+ assertEquals(date2, ((EventDataItem) dataList.get(2)).getStartDate());
+ }
+
+ public void testDataItemCollapsing_im() {
+ final String address1 = "address 1";
+ final String address2 = "address 2";
+ final String customProtocol1 = "custom 1";
+ final String customProtocol2 = "custom 2";
+
+ mValues1.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+ mValues4.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
+
+ mValues1.put(Im.DATA, address1);
+ mValues2.put(Im.DATA, address1);
+ mValues3.put(Im.DATA, address1);
+ mValues4.put(Im.DATA, address2);
+
+ mValues1.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM);
+ mValues2.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM);
+ mValues3.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM);
+ mValues4.put(Im.PROTOCOL, Im.PROTOCOL_AIM);
+
+ mValues1.put(Im.CUSTOM_PROTOCOL, customProtocol1);
+ mValues2.put(Im.CUSTOM_PROTOCOL, customProtocol1);
+ mValues3.put(Im.CUSTOM_PROTOCOL, customProtocol2);
+
+ final DataKind kind = mGoogleAccountType.getKindForMimetype(Im.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3, mValues4);
+
+ assertEquals(3, dataList.size());
+ assertEquals(address1, ((ImDataItem) dataList.get(0)).getData());
+ assertEquals(address1, ((ImDataItem) dataList.get(1)).getData());
+ assertEquals(address2, ((ImDataItem) dataList.get(2)).getData());
+
+ assertEquals(customProtocol1, ((ImDataItem) dataList.get(0)).getCustomProtocol());
+ assertEquals(customProtocol2, ((ImDataItem) dataList.get(1)).getCustomProtocol());
+ assertEquals(Im.PROTOCOL_AIM, (int) ((ImDataItem) dataList.get(2)).getProtocol());
+ }
+
+ public void testDataItemCollapsing_nickname() {
+ final String nickname1 = "nickname 1";
+ final String nickname2 = "nickname 2";
+
+ mValues1.put(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE);
+
+ mValues1.put(Nickname.NAME, nickname1);
+ mValues2.put(Nickname.NAME, nickname1);
+ mValues3.put(Nickname.NAME, nickname2);
+
+ final DataKind kind = mGoogleAccountType.getKindForMimetype(Nickname.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3);
+
+ assertEquals(2, dataList.size());
+ assertEquals(nickname1, ((NicknameDataItem) dataList.get(0)).getName());
+ assertEquals(nickname2, ((NicknameDataItem) dataList.get(1)).getName());
+ }
+
+ public void testDataItemCollapsing_note() {
+ final String note1 = "note 1";
+ final String note2 = "note 2";
+
+ mValues1.put(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, Note.CONTENT_ITEM_TYPE);
+
+ mValues1.put(Note.NOTE, note1);
+ mValues2.put(Note.NOTE, note1);
+ mValues3.put(Note.NOTE, note2);
+
+ DataKind kind = mGoogleAccountType.getKindForMimetype(Note.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3);
+
+ assertEquals(2, dataList.size());
+ assertEquals(note1, ((NoteDataItem) dataList.get(0)).getNote());
+ assertEquals(note2, ((NoteDataItem) dataList.get(1)).getNote());
+ }
+
+ public void testDataItemCollapsing_organization() {
+ final String company1 = "company1";
+ final String company2 = "company2";
+ final String title1 = "title1";
+ final String title2 = "title2";
+
+ mValues1.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
+ mValues4.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
+
+ mValues1.put(Organization.COMPANY, company1);
+ mValues2.put(Organization.COMPANY, company1);
+ mValues3.put(Organization.COMPANY, company1);
+ mValues4.put(Organization.COMPANY, company2);
+
+ mValues1.put(Organization.TITLE, title1);
+ mValues2.put(Organization.TITLE, title1);
+ mValues3.put(Organization.TITLE, title2);
+ mValues4.put(Organization.TITLE, title1);
+
+ final DataKind kind =
+ mGoogleAccountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3, mValues4);
+
+ assertEquals(3, dataList.size());
+ assertEquals(company1, ((OrganizationDataItem) dataList.get(0)).getCompany());
+ assertEquals(company1, ((OrganizationDataItem) dataList.get(1)).getCompany());
+ assertEquals(company2, ((OrganizationDataItem) dataList.get(2)).getCompany());
+
+ assertEquals(title1, ((OrganizationDataItem) dataList.get(0)).getTitle());
+ assertEquals(title2, ((OrganizationDataItem) dataList.get(1)).getTitle());
+ }
+
+ public void testDataItemCollapsing_phone() {
+ final String phone1 = "111-111-1111";
+ final String phone1a = "1111111111";
+ final String phone2 = "222-222-2222";
+
+ mValues1.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+
+ mValues1.put(Phone.NUMBER, phone1);
+ mValues2.put(Phone.NUMBER, phone1a);
+ mValues3.put(Phone.NUMBER, phone2);
+
+ mValues1.put(Phone.TYPE, Phone.TYPE_MOBILE);
+ mValues2.put(Phone.TYPE, Phone.TYPE_HOME);
+ mValues3.put(Phone.TYPE, Phone.TYPE_WORK);
+
+ final DataKind kind = mGoogleAccountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3);
+ assertEquals(2, dataList.size());
+ assertEquals(phone1, ((PhoneDataItem) dataList.get(0)).getNumber());
+ assertEquals(phone2, ((PhoneDataItem) dataList.get(1)).getNumber());
+ assertEquals(Phone.TYPE_MOBILE,
+ ((PhoneDataItem) dataList.get(0)).getKindTypeColumn(kind));
+ }
+
+ public void testDataItemCollapsing_relation() {
+ final String name1 = "name1";
+ final String name2 = "name2";
+ final String customRelation1 = "custom relation 1";
+ final String customRelation2 = "custom relation 2";
+
+ mValues1.put(Data.MIMETYPE, Relation.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, Relation.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, Relation.CONTENT_ITEM_TYPE);
+ mValues4.put(Data.MIMETYPE, Relation.CONTENT_ITEM_TYPE);
+
+ mValues1.put(Relation.NAME, name1);
+ mValues2.put(Relation.NAME, name1);
+ mValues3.put(Relation.NAME, name1);
+ mValues4.put(Relation.NAME, name2);
+
+ mValues1.put(Relation.TYPE, Relation.TYPE_CUSTOM);
+ mValues2.put(Relation.TYPE, Relation.TYPE_CUSTOM);
+ mValues3.put(Relation.TYPE, Relation.TYPE_CUSTOM);
+ mValues4.put(Relation.TYPE, Relation.TYPE_BROTHER);
+
+ mValues1.put(Relation.LABEL, customRelation1);
+ mValues2.put(Relation.LABEL, customRelation1);
+ mValues3.put(Relation.LABEL, customRelation2);
+
+ final DataKind kind = mGoogleAccountType.getKindForMimetype(Relation.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3, mValues4);
+
+ assertEquals(3, dataList.size());
+ assertEquals(name1, ((RelationDataItem) dataList.get(0)).getName());
+ assertEquals(name2, ((RelationDataItem) dataList.get(2)).getName());
+
+ assertEquals(customRelation1, ((RelationDataItem) dataList.get(0)).getLabel());
+ assertEquals(customRelation2, ((RelationDataItem) dataList.get(1)).getLabel());
+ }
+
+ public void testDataItemCollapsing_sip() {
+ final String sip1 = "sip 1";
+ final String sip2 = "sip 2";
+
+ mValues1.put(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE);
+
+ mValues1.put(SipAddress.SIP_ADDRESS, sip1);
+ mValues2.put(SipAddress.SIP_ADDRESS, sip1);
+ mValues3.put(SipAddress.SIP_ADDRESS, sip2);
+
+ mValues1.put(SipAddress.TYPE, SipAddress.TYPE_WORK);
+ mValues2.put(SipAddress.TYPE, SipAddress.TYPE_HOME);
+ mValues3.put(SipAddress.TYPE, SipAddress.TYPE_WORK);
+
+ final DataKind kind = mGoogleAccountType.getKindForMimetype(SipAddress.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3);
+
+ assertEquals(2, dataList.size());
+ assertEquals(sip1, ((SipAddressDataItem) dataList.get(0)).getSipAddress());
+ assertEquals(sip2, ((SipAddressDataItem) dataList.get(1)).getSipAddress());
+ }
+
+ public void testDataItemCollapsing_structuredName() {
+ final String displayName1 = "Display Name 1";
+ final String displayName2 = "Display Name 2";
+
+ mValues1.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+
+ mValues1.put(StructuredName.DISPLAY_NAME, displayName1);
+ mValues2.put(StructuredName.DISPLAY_NAME, displayName1);
+ mValues3.put(StructuredName.DISPLAY_NAME, displayName2);
+
+ final DataKind kind =
+ mGoogleAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3);
+
+ assertEquals(2, dataList.size());
+ assertEquals(displayName1, ((StructuredNameDataItem) dataList.get(0)).getDisplayName());
+ assertEquals(displayName2, ((StructuredNameDataItem) dataList.get(1)).getDisplayName());
+ }
+
+ public void testDataItemCollapsing_structuredPostal() {
+ final String formattedAddress1 = "Formatted Address 1";
+ final String formattedAddress2 = "Formatted Address 2";
+
+ mValues1.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
+
+ mValues1.put(StructuredPostal.FORMATTED_ADDRESS, formattedAddress1);
+ mValues2.put(StructuredPostal.FORMATTED_ADDRESS, formattedAddress1);
+ mValues3.put(StructuredPostal.FORMATTED_ADDRESS, formattedAddress2);
+
+ final DataKind kind =
+ mGoogleAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3);
+
+ assertEquals(2, dataList.size());
+ assertEquals(formattedAddress1,
+ ((StructuredPostalDataItem) dataList.get(0)).getFormattedAddress());
+ assertEquals(formattedAddress2,
+ ((StructuredPostalDataItem) dataList.get(1)).getFormattedAddress());
+ }
+
+ public void testDataItemCollapsing_website() {
+ final String url1 = "www.url1.com";
+ final String url2 = "www.url2.com";
+
+ mValues1.put(Data.MIMETYPE, Website.CONTENT_ITEM_TYPE);
+ mValues2.put(Data.MIMETYPE, Website.CONTENT_ITEM_TYPE);
+ mValues3.put(Data.MIMETYPE, Website.CONTENT_ITEM_TYPE);
+
+ mValues1.put(Website.URL, url1);
+ mValues2.put(Website.URL, url1);
+ mValues3.put(Website.URL, url2);
+
+ final DataKind kind = mGoogleAccountType.getKindForMimetype(Website.CONTENT_ITEM_TYPE);
+
+ final List<DataItem> dataList =
+ createDataItemsAndCollapse(kind, mValues1, mValues2, mValues3);
+
+ assertEquals(2, dataList.size());
+ assertEquals(url1, ((WebsiteDataItem) dataList.get(0)).getUrl());
+ assertEquals(url2, ((WebsiteDataItem) dataList.get(1)).getUrl());
+ }
+}
diff --git a/tests/src/com/android/contacts/common/preference/ContactsPreferencesTest.java b/tests/src/com/android/contacts/common/preference/ContactsPreferencesTest.java
new file mode 100644
index 0000000..26e811d
--- /dev/null
+++ b/tests/src/com/android/contacts/common/preference/ContactsPreferencesTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2015 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.common.preference;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.android.contacts.common.model.account.AccountWithDataSet;
+
+import junit.framework.Assert;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+@MediumTest
+public class ContactsPreferencesTest extends InstrumentationTestCase {
+
+ private static final String ACCOUNT_KEY = "ACCOUNT_KEY";
+
+ @Mock private Context mContext;
+ @Mock private Resources mResources;
+ @Mock private SharedPreferences mSharedPreferences;
+
+ private ContactsPreferences mContactsPreferences;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ System.setProperty("dexmaker.dexcache",
+ getInstrumentation().getTargetContext().getCacheDir().getPath());
+ MockitoAnnotations.initMocks(this);
+
+ Mockito.when(mContext.getResources()).thenReturn(mResources);
+ Mockito.when(mResources.getString(Mockito.anyInt()))
+ .thenReturn(ACCOUNT_KEY); // contact_editor_default_account_key
+
+ Mockito.when(mContext.getSharedPreferences(Mockito.anyString(), Mockito.anyInt()))
+ .thenReturn(mSharedPreferences);
+ Mockito.when(mSharedPreferences.contains(ContactsPreferences.SORT_ORDER_KEY))
+ .thenReturn(true);
+ Mockito.when(mSharedPreferences.contains(ContactsPreferences.DISPLAY_ORDER_KEY))
+ .thenReturn(true);
+
+ mContactsPreferences = new ContactsPreferences(mContext);
+ }
+
+ public void testGetSortOrderDefault() {
+ Mockito.when(mResources.getBoolean(Mockito.anyInt())).thenReturn(
+ false, // R.bool.config_sort_order_user_changeable
+ true // R.bool.config_default_sort_order_primary
+ );
+ Assert.assertEquals(ContactsPreferences.SORT_ORDER_PRIMARY,
+ mContactsPreferences.getSortOrder());
+ }
+
+ public void testGetSortOrder() {
+ Mockito.when(mResources.getBoolean(Mockito.anyInt())).thenReturn(
+ true // R.bool.config_sort_order_user_changeable
+ );
+ Mockito.when(mSharedPreferences.getInt(Mockito.eq(ContactsPreferences.SORT_ORDER_KEY),
+ Mockito.anyInt())).thenReturn(ContactsPreferences.SORT_ORDER_PRIMARY);
+ Assert.assertEquals(ContactsPreferences.SORT_ORDER_PRIMARY,
+ mContactsPreferences.getSortOrder());
+ }
+
+ public void testGetDisplayOrderDefault() {
+ Mockito.when(mResources.getBoolean(Mockito.anyInt())).thenReturn(
+ false, // R.bool.config_display_order_user_changeable
+ true // R.bool.config_default_display_order_primary
+ );
+ Assert.assertEquals(ContactsPreferences.DISPLAY_ORDER_PRIMARY,
+ mContactsPreferences.getDisplayOrder());
+ }
+
+ public void testGetDisplayOrder() {
+ Mockito.when(mResources.getBoolean(Mockito.anyInt())).thenReturn(
+ true // R.bool.config_display_order_user_changeable
+ );
+ Mockito.when(mSharedPreferences.getInt(Mockito.eq(ContactsPreferences.DISPLAY_ORDER_KEY),
+ Mockito.anyInt())).thenReturn(ContactsPreferences.DISPLAY_ORDER_PRIMARY);
+ Assert.assertEquals(ContactsPreferences.DISPLAY_ORDER_PRIMARY,
+ mContactsPreferences.getDisplayOrder());
+ }
+
+ public void testRefreshSortOrder() throws InterruptedException {
+ Mockito.when(mResources.getBoolean(Mockito.anyInt())).thenReturn(
+ true // R.bool.config_sort_order_user_changeable
+ );
+ Mockito.when(mSharedPreferences.getInt(Mockito.eq(ContactsPreferences.SORT_ORDER_KEY),
+ Mockito.anyInt())).thenReturn(ContactsPreferences.SORT_ORDER_PRIMARY,
+ ContactsPreferences.SORT_ORDER_ALTERNATIVE);
+
+ Assert.assertEquals(ContactsPreferences.SORT_ORDER_PRIMARY,
+ mContactsPreferences.getSortOrder());
+ mContactsPreferences.refreshValue(ContactsPreferences.SORT_ORDER_KEY);
+
+ Assert.assertEquals(ContactsPreferences.SORT_ORDER_ALTERNATIVE,
+ mContactsPreferences.getSortOrder());
+ }
+
+ public void testRefreshDisplayOrder() throws InterruptedException {
+ Mockito.when(mResources.getBoolean(Mockito.anyInt())).thenReturn(
+ true // R.bool.config_display_order_user_changeable
+ );
+ Mockito.when(mSharedPreferences.getInt(Mockito.eq(ContactsPreferences.DISPLAY_ORDER_KEY),
+ Mockito.anyInt())).thenReturn(ContactsPreferences.DISPLAY_ORDER_PRIMARY,
+ ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE);
+
+ Assert.assertEquals(ContactsPreferences.DISPLAY_ORDER_PRIMARY,
+ mContactsPreferences.getDisplayOrder());
+ mContactsPreferences.refreshValue(ContactsPreferences.DISPLAY_ORDER_KEY);
+
+ Assert.assertEquals(ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE,
+ mContactsPreferences.getDisplayOrder());
+ }
+
+ public void testRefreshDefaultAccount() throws InterruptedException {
+ Mockito.when(mResources.getBoolean(Mockito.anyInt())).thenReturn(
+ true // R.bool.config_default_account_user_changeable
+ );
+
+ Mockito.when(mSharedPreferences.getString(Mockito.eq(ACCOUNT_KEY), Mockito.anyString()))
+ .thenReturn(new AccountWithDataSet("name1", "type1", "dataset1").stringify(),
+ new AccountWithDataSet("name2", "type2", "dataset2").stringify());
+
+ Assert.assertEquals("name1", mContactsPreferences.getDefaultAccount());
+ mContactsPreferences.refreshValue(ACCOUNT_KEY);
+
+ Assert.assertEquals("name2", mContactsPreferences.getDefaultAccount());
+ }
+}
diff --git a/tests/src/com/android/contacts/common/test/FragmentTestActivity.java b/tests/src/com/android/contacts/common/test/FragmentTestActivity.java
new file mode 100644
index 0000000..5ae2d95
--- /dev/null
+++ b/tests/src/com/android/contacts/common/test/FragmentTestActivity.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 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.common.test;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+/**
+ * An activity that is used for testing fragments. A unit test starts this
+ * activity, adds a fragment and then tests the fragment.
+ */
+public class FragmentTestActivity extends Activity {
+
+ public final static int LAYOUT_ID = 1;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Normally fragment/activity onStart() methods will not be called when screen is locked.
+ // Use the following flags to ensure that activities can be show for testing.
+ final Window window = getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
+ WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+
+ final FrameLayout layout = new FrameLayout(this);
+ layout.setId(LAYOUT_ID);
+ setContentView(layout);
+ }
+}
diff --git a/tests/src/com/android/contacts/common/test/IntegrationTestUtils.java b/tests/src/com/android/contacts/common/test/IntegrationTestUtils.java
new file mode 100644
index 0000000..5457128
--- /dev/null
+++ b/tests/src/com/android/contacts/common/test/IntegrationTestUtils.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2011 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.common.test;
+
+import static android.os.PowerManager.ACQUIRE_CAUSES_WAKEUP;
+import static android.os.PowerManager.FULL_WAKE_LOCK;
+import static android.os.PowerManager.ON_AFTER_RELEASE;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.PowerManager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.google.common.base.Preconditions;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.ThreadSafe;
+
+/** Some utility methods for making integration testing smoother. */
+@ThreadSafe
+public class IntegrationTestUtils {
+ private static final String TAG = "IntegrationTestUtils";
+
+ private final Instrumentation mInstrumentation;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock") private PowerManager.WakeLock mWakeLock;
+
+ public IntegrationTestUtils(Instrumentation instrumentation) {
+ mInstrumentation = instrumentation;
+ }
+
+ /**
+ * Find a view by a given resource id, from the given activity, and click it, iff it is
+ * enabled according to {@link View#isEnabled()}.
+ */
+ public void clickButton(final Activity activity, final int buttonResourceId) throws Throwable {
+ runOnUiThreadAndGetTheResult(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ View view = activity.findViewById(buttonResourceId);
+ Assert.assertNotNull(view);
+ if (view.isEnabled()) {
+ view.performClick();
+ }
+ return null;
+ }
+ });
+ }
+
+ /** Returns the result of running {@link TextView#getText()} on the ui thread. */
+ public CharSequence getText(final TextView view) throws Throwable {
+ return runOnUiThreadAndGetTheResult(new Callable<CharSequence>() {
+ @Override
+ public CharSequence call() {
+ return view.getText();
+ }
+ });
+ }
+
+ // TODO: Move this class and the appropriate documentation into a test library, having checked
+ // first to see if exactly this code already exists or not.
+ /**
+ * Execute a callable on the ui thread, returning its result synchronously.
+ * <p>
+ * Waits for an idle sync on the main thread (see {@link Instrumentation#waitForIdle(Runnable)})
+ * before executing this callable.
+ */
+ public <T> T runOnUiThreadAndGetTheResult(Callable<T> callable) throws Throwable {
+ FutureTask<T> future = new FutureTask<T>(callable);
+ mInstrumentation.waitForIdle(future);
+ try {
+ return future.get();
+ } catch (ExecutionException e) {
+ // Unwrap the cause of the exception and re-throw it.
+ throw e.getCause();
+ }
+ }
+
+ /**
+ * Wake up the screen, useful in tests that want or need the screen to be on.
+ * <p>
+ * This is usually called from setUp() for tests that require it. After calling this method,
+ * {@link #releaseScreenWakeLock()} must be called, this is usually done from tearDown().
+ */
+ public void acquireScreenWakeLock(Context context) {
+ synchronized (mLock) {
+ Preconditions.checkState(mWakeLock == null, "mWakeLock was already held");
+ mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE))
+ .newWakeLock(
+ PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE | PowerManager.FULL_WAKE_LOCK, TAG);
+ mWakeLock.acquire();
+ }
+ }
+
+ /** Release the wake lock previously acquired with {@link #acquireScreenWakeLock(Context)}. */
+ public void releaseScreenWakeLock() {
+ synchronized (mLock) {
+ // We don't use Preconditions to force you to have acquired before release.
+ // This is because we don't want unnecessary exceptions in tearDown() since they'll
+ // typically mask the actual exception that happened during the test.
+ // The other reason is that this method is most likely to be called from tearDown(),
+ // which is invoked within a finally block, so it's not infrequently the case that
+ // the setUp() method fails before getting the lock, at which point we don't want
+ // to fail in tearDown().
+ if (mWakeLock != null) {
+ mWakeLock.release();
+ mWakeLock = null;
+ }
+ }
+ }
+
+ /**
+ * Gets all {@link TextView} objects whose {@link TextView#getText()} contains the given text as
+ * a substring.
+ */
+ public List<TextView> getTextViewsWithString(final Activity activity, final String text)
+ throws Throwable {
+ return getTextViewsWithString(getRootView(activity), text);
+ }
+
+ /**
+ * Gets all {@link TextView} objects whose {@link TextView#getText()} contains the given text as
+ * a substring for the given root view.
+ */
+ public List<TextView> getTextViewsWithString(final View rootView, final String text)
+ throws Throwable {
+ return runOnUiThreadAndGetTheResult(new Callable<List<TextView>>() {
+ @Override
+ public List<TextView> call() throws Exception {
+ List<TextView> matchingViews = new ArrayList<TextView>();
+ for (TextView textView : getAllViews(TextView.class, rootView)) {
+ if (textView.getText().toString().contains(text)) {
+ matchingViews.add(textView);
+ }
+ }
+ return matchingViews;
+ }
+ });
+ }
+
+ /** Find the root view for a given activity. */
+ public static View getRootView(Activity activity) {
+ return activity.findViewById(android.R.id.content).getRootView();
+ }
+
+ /**
+ * Gets a list of all views of a given type, rooted at the given parent.
+ * <p>
+ * This method will recurse down through all {@link ViewGroup} instances looking for
+ * {@link View} instances of the supplied class type. Specifically it will use the
+ * {@link Class#isAssignableFrom(Class)} method as the test for which views to add to the list,
+ * so if you provide {@code View.class} as your type, you will get every view. The parent itself
+ * will be included also, should it be of the right type.
+ * <p>
+ * This call manipulates the ui, and as such should only be called from the application's main
+ * thread.
+ */
+ private static <T extends View> List<T> getAllViews(final Class<T> clazz, final View parent) {
+ List<T> results = new ArrayList<T>();
+ if (parent.getClass().equals(clazz)) {
+ results.add(clazz.cast(parent));
+ }
+ if (parent instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) parent;
+ for (int i = 0; i < viewGroup.getChildCount(); ++i) {
+ results.addAll(getAllViews(clazz, viewGroup.getChildAt(i)));
+ }
+ }
+ return results;
+ }
+}
diff --git a/tests/src/com/android/contacts/common/test/LaunchPerformanceBase.java b/tests/src/com/android/contacts/common/test/LaunchPerformanceBase.java
new file mode 100644
index 0000000..a2ebde3
--- /dev/null
+++ b/tests/src/com/android/contacts/common/test/LaunchPerformanceBase.java
@@ -0,0 +1,50 @@
+/*
+ * 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.common.test;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Bundle;
+
+
+/**
+ * Base class for all launch performance Instrumentation classes.
+ */
+public class LaunchPerformanceBase extends Instrumentation {
+
+ public static final String LOG_TAG = "Launch Performance";
+
+ protected Bundle mResults;
+ protected Intent mIntent;
+
+ public LaunchPerformanceBase() {
+ mResults = new Bundle();
+ mIntent = new Intent(Intent.ACTION_MAIN);
+ mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ setAutomaticPerformanceSnapshots();
+ }
+
+ /**
+ * Launches intent, and waits for idle before returning.
+ *
+ * @hide
+ */
+ protected void LaunchApp() {
+ startActivitySync(mIntent);
+ waitForIdleSync();
+ }
+}
diff --git a/tests/src/com/android/contacts/common/test/mocks/ContactsMockContext.java b/tests/src/com/android/contacts/common/test/mocks/ContactsMockContext.java
new file mode 100644
index 0000000..c72fe3d
--- /dev/null
+++ b/tests/src/com/android/contacts/common/test/mocks/ContactsMockContext.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 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.common.test.mocks;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.provider.ContactsContract;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+
+/**
+ * A mock context for contacts unit tests. Forwards everything to
+ * a supplied context, except content resolver operations, which are sent
+ * to mock content providers.
+ */
+public class ContactsMockContext extends ContextWrapper {
+ private ContactsMockPackageManager mPackageManager;
+ private MockContentResolver mContentResolver;
+ private MockContentProvider mContactsProvider;
+ private MockContentProvider mSettingsProvider;
+ private Intent mIntentForStartActivity;
+
+ public ContactsMockContext(Context base) {
+ this(base, ContactsContract.AUTHORITY);
+ }
+
+ public ContactsMockContext(Context base, String authority) {
+ super(base);
+ mPackageManager = new ContactsMockPackageManager();
+ mContentResolver = new MockContentResolver();
+ mContactsProvider = new MockContentProvider();
+ mContentResolver.addProvider(authority, mContactsProvider);
+ mSettingsProvider = new MockContentProvider();
+ mContentResolver.addProvider(Settings.AUTHORITY, mSettingsProvider);
+ }
+
+ @Override
+ public ContentResolver getContentResolver() {
+ return mContentResolver;
+ }
+
+ public MockContentProvider getContactsProvider() {
+ return mContactsProvider;
+ }
+
+ public MockContentProvider getSettingsProvider() {
+ return mSettingsProvider;
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return this;
+ }
+
+ /**
+ * Instead of actually sending Intent, this method just remembers what Intent was supplied last.
+ * You can check the content via {@link #getIntentForStartActivity()} for verification.
+ */
+ @Override
+ public void startActivity(Intent intent) {
+ mIntentForStartActivity = intent;
+ }
+
+ public Intent getIntentForStartActivity() {
+ return mIntentForStartActivity;
+ }
+
+ public void verify() {
+ mContactsProvider.verify();
+ mSettingsProvider.verify();
+ }
+
+}
diff --git a/tests/src/com/android/contacts/common/test/mocks/ContactsMockPackageManager.java b/tests/src/com/android/contacts/common/test/mocks/ContactsMockPackageManager.java
new file mode 100644
index 0000000..a1557ff
--- /dev/null
+++ b/tests/src/com/android/contacts/common/test/mocks/ContactsMockPackageManager.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 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.common.test.mocks;
+
+import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.test.mock.MockPackageManager;
+
+/**
+ */
+public class ContactsMockPackageManager extends MockPackageManager {
+ public ContactsMockPackageManager() {
+ }
+
+ @Override
+ public Drawable getActivityLogo(ComponentName activityName) throws NameNotFoundException {
+ return new ColorDrawable();
+ }
+
+ @Override
+ public Drawable getActivityIcon(ComponentName activityName) {
+ return new ColorDrawable();
+ }
+
+ @Override
+ public Drawable getDrawable(String packageName, int resid, ApplicationInfo appInfo) {
+ // TODO: make programmable
+ return new ColorDrawable();
+ }
+}
diff --git a/tests/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java b/tests/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java
new file mode 100644
index 0000000..b46c49d
--- /dev/null
+++ b/tests/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2010 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.common.test.mocks;
+
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountTypeWithDataSet;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.BaseAccountType;
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A mock {@link AccountTypeManager} class.
+ */
+public class MockAccountTypeManager extends AccountTypeManager {
+
+ public AccountType[] mTypes;
+ public AccountWithDataSet[] mAccounts;
+
+ public MockAccountTypeManager(AccountType[] types, AccountWithDataSet[] accounts) {
+ this.mTypes = types;
+ this.mAccounts = accounts;
+ }
+
+ @Override
+ public AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet) {
+ // Add fallback accountType to mimic the behavior of AccountTypeManagerImpl
+ AccountType mFallbackAccountType = new BaseAccountType() {
+ @Override
+ public boolean areContactsWritable() {
+ return false;
+ }
+ };
+ mFallbackAccountType.accountType = "fallback";
+ for (AccountType type : mTypes) {
+ if (Objects.equal(accountTypeWithDataSet.accountType, type.accountType)
+ && Objects.equal(accountTypeWithDataSet.dataSet, type.dataSet)) {
+ return type;
+ }
+ }
+ return mFallbackAccountType;
+ }
+
+ @Override
+ public List<AccountWithDataSet> getAccounts(boolean writableOnly) {
+ return Arrays.asList(mAccounts);
+ }
+
+ @Override
+ public void sortAccounts(AccountWithDataSet account) {}
+
+ @Override
+ public List<AccountWithDataSet> getGroupWritableAccounts() {
+ return Arrays.asList(mAccounts);
+ }
+
+ @Override
+ public Map<AccountTypeWithDataSet, AccountType> getUsableInvitableAccountTypes() {
+ return Maps.newHashMap(); // Always returns empty
+ }
+
+ @Override
+ public List<AccountType> getAccountTypes(boolean writableOnly) {
+ final List<AccountType> ret = Lists.newArrayList();
+ synchronized (this) {
+ for (AccountType type : mTypes) {
+ if (!writableOnly || type.areContactsWritable()) {
+ ret.add(type);
+ }
+ }
+ }
+ return ret;
+ }
+}
diff --git a/tests/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java b/tests/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java
new file mode 100644
index 0000000..db8f06f
--- /dev/null
+++ b/tests/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011 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.common.test.mocks;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.contacts.common.ContactPhotoManager;
+
+/**
+ * A photo preloader that always uses the "no contact" picture and never executes any real
+ * db queries
+ */
+public class MockContactPhotoManager extends ContactPhotoManager {
+ @Override
+ public void loadThumbnail(ImageView view, long photoId, boolean darkTheme, boolean isCircular,
+ DefaultImageRequest defaultImageRequest, DefaultImageProvider defaultProvider) {
+ defaultProvider.applyDefaultImage(view, -1, darkTheme, null);
+ }
+
+ @Override
+ public void loadPhoto(ImageView view, Uri photoUri, int requestedExtent, boolean darkTheme,
+ boolean isCircular, DefaultImageRequest defaultImageRequest,
+ DefaultImageProvider defaultProvider) {
+ defaultProvider.applyDefaultImage(view, requestedExtent, darkTheme, null);
+ }
+
+ @Override
+ public void removePhoto(ImageView view) {
+ view.setImageDrawable(null);
+ }
+
+ @Override
+ public void cancelPendingRequests(View fragmentRootView) {
+ }
+
+ @Override
+ public void pause() {
+ }
+
+ @Override
+ public void resume() {
+ }
+
+ @Override
+ public void refreshCache() {
+ }
+
+ @Override
+ public void cacheBitmap(Uri photoUri, Bitmap bitmap, byte[] photoBytes) {
+ }
+
+ @Override
+ public void preloadPhotosInBackground() {
+ }
+}
diff --git a/tests/src/com/android/contacts/common/test/mocks/MockContentProvider.java b/tests/src/com/android/contacts/common/test/mocks/MockContentProvider.java
new file mode 100644
index 0000000..335e8d2
--- /dev/null
+++ b/tests/src/com/android/contacts/common/test/mocks/MockContentProvider.java
@@ -0,0 +1,659 @@
+/*
+ * Copyright (C) 2010 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.common.test.mocks;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.support.annotation.Nullable;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A programmable mock content provider.
+ */
+public class MockContentProvider extends android.test.mock.MockContentProvider {
+ private static final String TAG = "MockContentProvider";
+
+ public static class Query {
+
+ private final Uri mUri;
+ private String[] mProjection;
+ private String[] mDefaultProjection;
+ private String mSelection;
+ private String[] mSelectionArgs;
+ private String mSortOrder;
+ private List<Object> mRows = new ArrayList<>();
+ private boolean mAnyProjection;
+ private boolean mAnySelection;
+ private boolean mAnySortOrder;
+ private boolean mAnyNumberOfTimes;
+
+ private boolean mExecuted;
+
+ public Query(Uri uri) {
+ mUri = uri;
+ }
+
+ @Override
+ public String toString() {
+ return queryToString(mUri, mProjection, mSelection, mSelectionArgs, mSortOrder);
+ }
+
+ public Query withProjection(String... projection) {
+ mProjection = projection;
+ return this;
+ }
+
+ public Query withDefaultProjection(String... projection) {
+ mDefaultProjection = projection;
+ return this;
+ }
+
+ public Query withAnyProjection() {
+ mAnyProjection = true;
+ return this;
+ }
+
+ public Query withSelection(String selection, String... selectionArgs) {
+ mSelection = selection;
+ mSelectionArgs = selectionArgs;
+ return this;
+ }
+
+ public Query withAnySelection() {
+ mAnySelection = true;
+ return this;
+ }
+
+ public Query withSortOrder(String sortOrder) {
+ mSortOrder = sortOrder;
+ return this;
+ }
+
+ public Query withAnySortOrder() {
+ mAnySortOrder = true;
+ return this;
+ }
+
+ public Query returnRow(ContentValues values) {
+ mRows.add(values);
+ return this;
+ }
+
+ public Query returnRow(Object... row) {
+ mRows.add(row);
+ return this;
+ }
+
+ public Query returnEmptyCursor() {
+ mRows.clear();
+ return this;
+ }
+
+ public Query anyNumberOfTimes() {
+ mAnyNumberOfTimes = true;
+ return this;
+ }
+
+ public boolean equals(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ if (!uri.equals(mUri)) {
+ return false;
+ }
+
+ if (!mAnyProjection && !Arrays.equals(projection, mProjection)) {
+ return false;
+ }
+
+ if (!mAnySelection && !Objects.equals(selection, mSelection)) {
+ return false;
+ }
+
+ if (!mAnySelection && !Arrays.equals(selectionArgs, mSelectionArgs)) {
+ return false;
+ }
+
+ if (!mAnySortOrder && !Objects.equals(sortOrder, mSortOrder)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public Cursor getResult(String[] projection) {
+ String[] columnNames;
+ if (mAnyProjection) {
+ columnNames = projection;
+ } else {
+ columnNames = mProjection != null ? mProjection : mDefaultProjection;
+ }
+
+ MatrixCursor cursor = new MatrixCursor(columnNames);
+ for (Object row : mRows) {
+ if (row instanceof Object[]) {
+ cursor.addRow((Object[]) row);
+ } else {
+ ContentValues values = (ContentValues) row;
+ Object[] columns = new Object[projection.length];
+ for (int i = 0; i < projection.length; i++) {
+ columns[i] = values.get(projection[i]);
+ }
+ cursor.addRow(columns);
+ }
+ }
+ return cursor;
+ }
+ }
+
+ public static class TypeQuery {
+ private final Uri mUri;
+ private final String mType;
+
+ public TypeQuery(Uri uri, String type) {
+ mUri = uri;
+ mType = type;
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ public String getType() {
+ return mType;
+ }
+
+ @Override
+ public String toString() {
+ return mUri + " --> " + mType;
+ }
+
+ public boolean equals(Uri uri) {
+ return getUri().equals(uri);
+ }
+ }
+
+ public static class Insert {
+ private final Uri mUri;
+ private final ContentValues mContentValues;
+ private final Uri mResultUri;
+ private boolean mAnyNumberOfTimes;
+ private boolean mIsExecuted;
+
+ /**
+ * Creates a new Insert to expect.
+ *
+ * @param uri the uri of the insertion request.
+ * @param contentValues the ContentValues to insert.
+ * @param resultUri the {@link Uri} for the newly inserted item.
+ * @throws NullPointerException if any parameter is {@code null}.
+ */
+ public Insert(Uri uri, ContentValues contentValues, Uri resultUri) {
+ mUri = Preconditions.checkNotNull(uri);
+ mContentValues = Preconditions.checkNotNull(contentValues);
+ mResultUri = Preconditions.checkNotNull(resultUri);
+ }
+
+ /**
+ * Causes this insert expectation to be useable for mutliple calls to insert, rather than
+ * just one.
+ *
+ * @return this
+ */
+ public Insert anyNumberOfTimes() {
+ mAnyNumberOfTimes = true;
+ return this;
+ }
+
+ private boolean equals(Uri uri, ContentValues contentValues) {
+ return mUri.equals(uri) && mContentValues.equals(contentValues);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Insert insert = (Insert) o;
+ return mAnyNumberOfTimes == insert.mAnyNumberOfTimes &&
+ mIsExecuted == insert.mIsExecuted &&
+ Objects.equals(mUri, insert.mUri) &&
+ Objects.equals(mContentValues, insert.mContentValues) &&
+ Objects.equals(mResultUri, insert.mResultUri);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUri, mContentValues, mResultUri, mAnyNumberOfTimes, mIsExecuted);
+ }
+
+ @Override
+ public String toString() {
+ return "Insert{" +
+ "mUri=" + mUri +
+ ", mContentValues=" + mContentValues +
+ ", mResultUri=" + mResultUri +
+ ", mAnyNumberOfTimes=" + mAnyNumberOfTimes +
+ ", mIsExecuted=" + mIsExecuted +
+ '}';
+ }
+ }
+
+ public static class Delete {
+ private final Uri mUri;
+
+ private boolean mAnyNumberOfTimes;
+ private boolean mAnySelection;
+ @Nullable private String mSelection;
+ @Nullable private String[] mSelectionArgs;
+ private boolean mIsExecuted;
+ private int mRowsAffected;
+
+ /**
+ * Creates a new Delete to expect.
+ * @param uri the uri of the delete request.
+ * @throws NullPointerException if uri is {@code null}.
+ */
+ public Delete(Uri uri) {
+ mUri = Preconditions.checkNotNull(uri);
+ }
+
+ /**
+ * Sets the given information as expected selection arguments.
+ *
+ * @param selection The selection to expect.
+ * @param selectionArgs The selection args to expect.
+ * @return this.
+ */
+ public Delete withSelection(String selection, @Nullable String[] selectionArgs) {
+ mSelection = Preconditions.checkNotNull(selection);
+ mSelectionArgs = selectionArgs;
+ mAnySelection = false;
+ return this;
+ }
+
+ /**
+ * Sets this delete to expect any selection arguments.
+ *
+ * @return this.
+ */
+ public Delete withAnySelection() {
+ mAnySelection = true;
+ return this;
+ }
+
+ /**
+ * Sets this delete to return the given number of rows affected.
+ *
+ * @param rowsAffected The value to return when this expected delete is executed.
+ * @return this.
+ */
+ public Delete returnRowsAffected(int rowsAffected) {
+ mRowsAffected = rowsAffected;
+ return this;
+ }
+
+ /**
+ * Causes this delete expectation to be useable for multiple calls to delete, rather than
+ * just one.
+ *
+ * @return this.
+ */
+ public Delete anyNumberOfTimes() {
+ mAnyNumberOfTimes = true;
+ return this;
+ }
+
+ private boolean equals(Uri uri, String selection, String[] selectionArgs) {
+ return mUri.equals(uri) && Objects.equals(mSelection, selection)
+ && Arrays.equals(mSelectionArgs, selectionArgs);
+ }
+ }
+
+ public static class Update {
+ private final Uri mUri;
+ private final ContentValues mContentValues;
+ @Nullable private String mSelection;
+ @Nullable private String[] mSelectionArgs;
+ private boolean mAnyNumberOfTimes;
+ private boolean mIsExecuted;
+ private int mRowsAffected;
+
+ /**
+ * Creates a new Update to expect.
+ *
+ * @param uri the uri of the update request.
+ * @param contentValues the ContentValues to update.
+ *
+ * @throws NullPointerException if any parameter is {@code null}.
+ */
+ public Update(Uri uri,
+ ContentValues contentValues,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ mUri = Preconditions.checkNotNull(uri);
+ mContentValues = Preconditions.checkNotNull(contentValues);
+ mSelection = selection;
+ mSelectionArgs = selectionArgs;
+ }
+
+ /**
+ * Causes this update expectation to be useable for mutliple calls to update, rather than
+ * just one.
+ *
+ * @return this
+ */
+ public Update anyNumberOfTimes() {
+ mAnyNumberOfTimes = true;
+ return this;
+ }
+
+ /**
+ * Sets this update to return the given number of rows affected.
+ *
+ * @param rowsAffected The value to return when this expected update is executed.
+ * @return this.
+ */
+ public Update returnRowsAffected(int rowsAffected) {
+ mRowsAffected = rowsAffected;
+ return this;
+ }
+
+ private boolean equals(Uri uri,
+ ContentValues contentValues,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ return mUri.equals(uri) && mContentValues.equals(contentValues) &&
+ Objects.equals(mSelection, selection) &&
+ Objects.equals(mSelectionArgs, selectionArgs);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Update update = (Update) o;
+ return mAnyNumberOfTimes == update.mAnyNumberOfTimes &&
+ mIsExecuted == update.mIsExecuted &&
+ Objects.equals(mUri, update.mUri) &&
+ Objects.equals(mContentValues, update.mContentValues) &&
+ Objects.equals(mSelection, update.mSelection) &&
+ Objects.equals(mSelectionArgs, update.mSelectionArgs);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUri, mContentValues, mAnyNumberOfTimes, mIsExecuted, mSelection,
+ mSelectionArgs);
+ }
+
+ @Override
+ public String toString() {
+ return "Update{" +
+ "mUri=" + mUri +
+ ", mContentValues=" + mContentValues +
+ ", mAnyNumberOfTimes=" + mAnyNumberOfTimes +
+ ", mIsExecuted=" + mIsExecuted +
+ ", mSelection=" + mSelection +
+ ", mSelectionArgs=" + mSelectionArgs +
+ '}';
+ }
+ }
+
+ private List<Query> mExpectedQueries = new ArrayList<>();
+ private Map<Uri, String> mExpectedTypeQueries = Maps.newHashMap();
+ private List<Insert> mExpectedInserts = new ArrayList<>();
+ private List<Delete> mExpectedDeletes = new ArrayList<>();
+ private List<Update> mExpectedUpdates = new ArrayList<>();
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ public Query expectQuery(Uri contentUri) {
+ Query query = new Query(contentUri);
+ mExpectedQueries.add(query);
+ return query;
+ }
+
+ public void expectTypeQuery(Uri uri, String type) {
+ mExpectedTypeQueries.put(uri, type);
+ }
+
+ public void expectInsert(Uri contentUri, ContentValues contentValues, Uri resultUri) {
+ mExpectedInserts.add(new Insert(contentUri, contentValues, resultUri));
+ }
+
+ public Update expectUpdate(Uri contentUri,
+ ContentValues contentValues,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ Update update = new Update(contentUri, contentValues, selection, selectionArgs);
+ mExpectedUpdates.add(update);
+ return update;
+ }
+
+ public Delete expectDelete(Uri contentUri) {
+ Delete delete = new Delete(contentUri);
+ mExpectedDeletes.add(delete);
+ return delete;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ if (mExpectedQueries.isEmpty()) {
+ Assert.fail("Unexpected query: Actual:"
+ + queryToString(uri, projection, selection, selectionArgs, sortOrder));
+ }
+
+ for (Iterator<Query> iterator = mExpectedQueries.iterator(); iterator.hasNext();) {
+ Query query = iterator.next();
+ if (query.equals(uri, projection, selection, selectionArgs, sortOrder)) {
+ query.mExecuted = true;
+ if (!query.mAnyNumberOfTimes) {
+ iterator.remove();
+ }
+ return query.getResult(projection);
+ }
+ }
+
+ Assert.fail("Incorrect query. Expected one of: " + mExpectedQueries + ". Actual: " +
+ queryToString(uri, projection, selection, selectionArgs, sortOrder));
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ if (mExpectedTypeQueries.isEmpty()) {
+ Assert.fail("Unexpected getType query: " + uri);
+ }
+
+ String mimeType = mExpectedTypeQueries.get(uri);
+ if (mimeType != null) {
+ return mimeType;
+ }
+
+ Assert.fail("Unknown mime type for: " + uri);
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ if (mExpectedInserts.isEmpty()) {
+ Assert.fail("Unexpected insert. Actual: " + insertToString(uri, values));
+ }
+ for (Iterator<Insert> iterator = mExpectedInserts.iterator(); iterator.hasNext(); ) {
+ Insert insert = iterator.next();
+ if (insert.equals(uri, values)) {
+ insert.mIsExecuted = true;
+ if (!insert.mAnyNumberOfTimes) {
+ iterator.remove();
+ }
+ return insert.mResultUri;
+ }
+ }
+
+ Assert.fail("Incorrect insert. Expected one of: " + mExpectedInserts + ". Actual: "
+ + insertToString(uri, values));
+ return null;
+ }
+
+ private String insertToString(Uri uri, ContentValues contentValues) {
+ return "Insert { uri=" + uri + ", contentValues=" + contentValues + '}';
+ }
+
+ @Override
+ public int update(Uri uri,
+ ContentValues values,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ if (mExpectedUpdates.isEmpty()) {
+ Assert.fail("Unexpected update. Actual: "
+ + updateToString(uri, values, selection, selectionArgs));
+ }
+ for (Iterator<Update> iterator = mExpectedUpdates.iterator(); iterator.hasNext(); ) {
+ Update update = iterator.next();
+ if (update.equals(uri, values, selection, selectionArgs)) {
+ update.mIsExecuted = true;
+ if (!update.mAnyNumberOfTimes) {
+ iterator.remove();
+ }
+ return update.mRowsAffected;
+ }
+ }
+
+ Assert.fail("Incorrect update. Expected one of: " + mExpectedUpdates + ". Actual: "
+ + updateToString(uri, values, selection, selectionArgs));
+ return - 1;
+ }
+
+ private String updateToString(Uri uri,
+ ContentValues contentValues,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ return "Update { uri=" + uri + ", contentValues=" + contentValues + ", selection=" +
+ selection + ", selectionArgs" + Arrays.toString(selectionArgs) + '}';
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ if (mExpectedDeletes.isEmpty()) {
+ Assert.fail("Unexpected delete. Actual: " + deleteToString(uri, selection,
+ selectionArgs));
+ }
+ for (Iterator<Delete> iterator = mExpectedDeletes.iterator(); iterator.hasNext(); ) {
+ Delete delete = iterator.next();
+ if (delete.equals(uri, selection, selectionArgs)) {
+ delete.mIsExecuted = true;
+ if (!delete.mAnyNumberOfTimes) {
+ iterator.remove();
+ }
+ return delete.mRowsAffected;
+ }
+ }
+ Assert.fail("Incorrect delete. Expected one of: " + mExpectedDeletes + ". Actual: "
+ + deleteToString(uri, selection, selectionArgs));
+ return -1;
+ }
+
+ private String deleteToString(Uri uri, String selection, String[] selectionArgs) {
+ return "Delete { uri=" + uri + ", selection=" + selection + ", selectionArgs"
+ + Arrays.toString(selectionArgs) + '}';
+ }
+
+ private static String queryToString(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(uri).append(" ");
+ if (projection != null) {
+ sb.append(Arrays.toString(projection));
+ } else {
+ sb.append("[]");
+ }
+ if (selection != null) {
+ sb.append(" selection: '").append(selection).append("'");
+ if (selectionArgs != null) {
+ sb.append(Arrays.toString(selectionArgs));
+ } else {
+ sb.append("[]");
+ }
+ }
+ if (sortOrder != null) {
+ sb.append(" sort: '").append(sortOrder).append("'");
+ }
+ return sb.toString();
+ }
+
+ public void verify() {
+ verifyQueries();
+ verifyInserts();
+ verifyDeletes();
+ }
+
+ private void verifyQueries() {
+ List<Query> missedQueries = new ArrayList<>();
+ for (Query query : mExpectedQueries) {
+ if (!query.mExecuted) {
+ missedQueries.add(query);
+ }
+ }
+ Assert.assertTrue("Not all expected queries have been called: " + missedQueries,
+ missedQueries.isEmpty());
+ }
+
+ private void verifyInserts() {
+ List<Insert> missedInserts = new ArrayList<>();
+ for (Insert insert : mExpectedInserts) {
+ if (!insert.mIsExecuted) {
+ missedInserts.add(insert);
+ }
+ }
+ Assert.assertTrue("Not all expected inserts have been called: " + missedInserts,
+ missedInserts.isEmpty());
+ }
+
+ private void verifyDeletes() {
+ List<Delete> missedDeletes = new ArrayList<>();
+ for (Delete delete : mExpectedDeletes) {
+ if (!delete.mIsExecuted) {
+ missedDeletes.add(delete);
+ }
+ }
+ Assert.assertTrue("Not all expected deletes have been called: " + missedDeletes,
+ missedDeletes.isEmpty());
+ }
+}
diff --git a/tests/src/com/android/contacts/common/test/mocks/MockSharedPreferences.java b/tests/src/com/android/contacts/common/test/mocks/MockSharedPreferences.java
new file mode 100644
index 0000000..13d035e
--- /dev/null
+++ b/tests/src/com/android/contacts/common/test/mocks/MockSharedPreferences.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010 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.common.test.mocks;
+
+import android.content.SharedPreferences;
+
+import com.google.common.collect.Maps;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * A programmable mock content provider.
+ */
+public class MockSharedPreferences implements SharedPreferences, SharedPreferences.Editor {
+
+ private HashMap<String, Object> mValues = Maps.newHashMap();
+ private HashMap<String, Object> mTempValues = Maps.newHashMap();
+
+ public Editor edit() {
+ return this;
+ }
+
+ public boolean contains(String key) {
+ return mValues.containsKey(key);
+ }
+
+ public Map<String, ?> getAll() {
+ return new HashMap<String, Object>(mValues);
+ }
+
+ public boolean getBoolean(String key, boolean defValue) {
+ if (mValues.containsKey(key)) {
+ return ((Boolean)mValues.get(key)).booleanValue();
+ }
+ return defValue;
+ }
+
+ public float getFloat(String key, float defValue) {
+ if (mValues.containsKey(key)) {
+ return ((Float)mValues.get(key)).floatValue();
+ }
+ return defValue;
+ }
+
+ public int getInt(String key, int defValue) {
+ if (mValues.containsKey(key)) {
+ return ((Integer)mValues.get(key)).intValue();
+ }
+ return defValue;
+ }
+
+ public long getLong(String key, long defValue) {
+ if (mValues.containsKey(key)) {
+ return ((Long)mValues.get(key)).longValue();
+ }
+ return defValue;
+ }
+
+ public String getString(String key, String defValue) {
+ if (mValues.containsKey(key))
+ return (String)mValues.get(key);
+ return defValue;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Set<String> getStringSet(String key, Set<String> defValues) {
+ if (mValues.containsKey(key)) {
+ return (Set<String>) mValues.get(key);
+ }
+ return defValues;
+ }
+
+ public void registerOnSharedPreferenceChangeListener(
+ OnSharedPreferenceChangeListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void unregisterOnSharedPreferenceChangeListener(
+ OnSharedPreferenceChangeListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Editor putBoolean(String key, boolean value) {
+ mTempValues.put(key, Boolean.valueOf(value));
+ return this;
+ }
+
+ public Editor putFloat(String key, float value) {
+ mTempValues.put(key, value);
+ return this;
+ }
+
+ public Editor putInt(String key, int value) {
+ mTempValues.put(key, value);
+ return this;
+ }
+
+ public Editor putLong(String key, long value) {
+ mTempValues.put(key, value);
+ return this;
+ }
+
+ public Editor putString(String key, String value) {
+ mTempValues.put(key, value);
+ return this;
+ }
+
+ public Editor putStringSet(String key, Set<String> values) {
+ mTempValues.put(key, values);
+ return this;
+ }
+
+ public Editor remove(String key) {
+ mTempValues.remove(key);
+ return this;
+ }
+
+ public Editor clear() {
+ mTempValues.clear();
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean commit() {
+ mValues = (HashMap<String, Object>)mTempValues.clone();
+ return true;
+ }
+
+ public void apply() {
+ commit();
+ }
+}
diff --git a/tests/src/com/android/contacts/common/tests/testauth/TestAuthenticationService.java b/tests/src/com/android/contacts/common/tests/testauth/TestAuthenticationService.java
new file mode 100644
index 0000000..93d1f4a
--- /dev/null
+++ b/tests/src/com/android/contacts/common/tests/testauth/TestAuthenticationService.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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.common.tests.testauth;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+public abstract class TestAuthenticationService extends Service {
+
+ private TestAuthenticator mAuthenticator;
+
+ @Override
+ public void onCreate() {
+ Log.v(TestauthConstants.LOG_TAG, this + " Service started.");
+ mAuthenticator = new TestAuthenticator(this);
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.v(TestauthConstants.LOG_TAG, this + " Service stopped.");
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Log.v(TestauthConstants.LOG_TAG, this + " getBinder() intent=" + intent);
+ return mAuthenticator.getIBinder();
+ }
+
+ public static class Basic extends TestAuthenticationService {
+ }
+}
diff --git a/tests/src/com/android/contacts/common/tests/testauth/TestAuthenticator.java b/tests/src/com/android/contacts/common/tests/testauth/TestAuthenticator.java
new file mode 100644
index 0000000..2f676c7
--- /dev/null
+++ b/tests/src/com/android/contacts/common/tests/testauth/TestAuthenticator.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 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.common.tests.testauth;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+/**
+ * Simple authenticator. It has no "login" dialogs/activities. When you add a new account, it'll
+ * just create a new account with a unique name.
+ */
+class TestAuthenticator extends AbstractAccountAuthenticator {
+ private static final String PASSWORD = "xxx"; // any string will do.
+
+ // To remember the last user-ID.
+ private static final String PREF_KEY_LAST_USER_ID = "TestAuthenticator.PREF_KEY_LAST_USER_ID";
+
+ private final Context mContext;
+
+ public TestAuthenticator(Context context) {
+ super(context);
+ mContext = context.getApplicationContext();
+ }
+
+ /**
+ * @return a new, unique username.
+ */
+ private String newUniqueUserName() {
+ final SharedPreferences prefs =
+ PreferenceManager.getDefaultSharedPreferences(mContext);
+ final int nextId = prefs.getInt(PREF_KEY_LAST_USER_ID, 0) + 1;
+ prefs.edit().putInt(PREF_KEY_LAST_USER_ID, nextId).apply();
+
+ return "User-" + nextId;
+ }
+
+ /**
+ * Create a new account with the name generated by {@link #newUniqueUserName()}.
+ */
+ @Override
+ public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
+ String authTokenType, String[] requiredFeatures, Bundle options) {
+ Log.v(TestauthConstants.LOG_TAG, "addAccount() type=" + accountType);
+ final Bundle bundle = new Bundle();
+
+ final Account account = new Account(newUniqueUserName(), accountType);
+
+ // Create an account.
+ AccountManager.get(mContext).addAccountExplicitly(account, PASSWORD, null);
+
+ // And return it.
+ bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+ return bundle;
+ }
+
+ /**
+ * Just return the user name as the authtoken.
+ */
+ @Override
+ public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
+ String authTokenType, Bundle loginOptions) {
+ Log.v(TestauthConstants.LOG_TAG, "getAuthToken() account=" + account);
+ final Bundle bundle = new Bundle();
+ bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+ bundle.putString(AccountManager.KEY_AUTHTOKEN, account.name);
+
+ return bundle;
+ }
+
+ @Override
+ public Bundle confirmCredentials(
+ AccountAuthenticatorResponse response, Account account, Bundle options) {
+ Log.v(TestauthConstants.LOG_TAG, "confirmCredentials()");
+ return null;
+ }
+
+ @Override
+ public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+ Log.v(TestauthConstants.LOG_TAG, "editProperties()");
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getAuthTokenLabel(String authTokenType) {
+ // null means we don't support multiple authToken types
+ Log.v(TestauthConstants.LOG_TAG, "getAuthTokenLabel()");
+ return null;
+ }
+
+ @Override
+ public Bundle hasFeatures(
+ AccountAuthenticatorResponse response, Account account, String[] features) {
+ // This call is used to query whether the Authenticator supports
+ // specific features. We don't expect to get called, so we always
+ // return false (no) for any queries.
+ Log.v(TestauthConstants.LOG_TAG, "hasFeatures()");
+ final Bundle result = new Bundle();
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+ return result;
+ }
+
+ @Override
+ public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
+ String authTokenType, Bundle loginOptions) {
+ Log.v(TestauthConstants.LOG_TAG, "updateCredentials()");
+ return null;
+ }
+}
diff --git a/tests/src/com/android/contacts/common/tests/testauth/TestSyncAdapter.java b/tests/src/com/android/contacts/common/tests/testauth/TestSyncAdapter.java
new file mode 100644
index 0000000..a7c0f83
--- /dev/null
+++ b/tests/src/com/android/contacts/common/tests/testauth/TestSyncAdapter.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 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.common.tests.testauth;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.provider.ContactsContract.RawContacts;
+import android.util.Log;
+
+/**
+ * Simple (minimal) sync adapter.
+ *
+ */
+public class TestSyncAdapter extends AbstractThreadedSyncAdapter {
+ private final AccountManager mAccountManager;
+
+ private final Context mContext;
+
+ public TestSyncAdapter(Context context, boolean autoInitialize) {
+ super(context, autoInitialize);
+ mContext = context.getApplicationContext();
+ mAccountManager = AccountManager.get(mContext);
+ }
+
+ /**
+ * Doesn't actually sync, but sweep up all existing local-only contacts.
+ */
+ @Override
+ public void onPerformSync(Account account, Bundle extras, String authority,
+ ContentProviderClient provider, SyncResult syncResult) {
+ Log.v(TestauthConstants.LOG_TAG, "TestSyncAdapter.onPerformSync() account=" + account);
+
+ // First, claim all local-only contacts, if any.
+ ContentResolver cr = mContext.getContentResolver();
+ ContentValues values = new ContentValues();
+ values.put(RawContacts.ACCOUNT_NAME, account.name);
+ values.put(RawContacts.ACCOUNT_TYPE, account.type);
+ final int count = cr.update(RawContacts.CONTENT_URI, values,
+ RawContacts.ACCOUNT_NAME + " IS NULL AND " + RawContacts.ACCOUNT_TYPE + " IS NULL",
+ null);
+ if (count > 0) {
+ Log.v(TestauthConstants.LOG_TAG, "Claimed " + count + " local raw contacts");
+ }
+
+ // TODO: Clear isDirty flag
+ // TODO: Remove isDeleted raw contacts
+ }
+}
diff --git a/tests/src/com/android/contacts/common/tests/testauth/TestSyncService.java b/tests/src/com/android/contacts/common/tests/testauth/TestSyncService.java
new file mode 100644
index 0000000..3354cb4
--- /dev/null
+++ b/tests/src/com/android/contacts/common/tests/testauth/TestSyncService.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 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.common.tests.testauth;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public abstract class TestSyncService extends Service {
+
+ private static TestSyncAdapter sSyncAdapter;
+
+ @Override
+ public void onCreate() {
+ if (sSyncAdapter == null) {
+ sSyncAdapter = new TestSyncAdapter(getApplicationContext(), true);
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return sSyncAdapter.getSyncAdapterBinder();
+ }
+
+ public static class Basic extends TestSyncService {
+ }
+}
diff --git a/tests/src/com/android/contacts/common/tests/testauth/TestauthConstants.java b/tests/src/com/android/contacts/common/tests/testauth/TestauthConstants.java
new file mode 100644
index 0000000..3ce7f5a
--- /dev/null
+++ b/tests/src/com/android/contacts/common/tests/testauth/TestauthConstants.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 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.common.tests.testauth;
+
+class TestauthConstants {
+ public static final String LOG_TAG = "Testauth";
+}
diff --git a/tests/src/com/android/contacts/common/util/BitmapUtilTests.java b/tests/src/com/android/contacts/common/util/BitmapUtilTests.java
new file mode 100644
index 0000000..94394b1
--- /dev/null
+++ b/tests/src/com/android/contacts/common/util/BitmapUtilTests.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import android.graphics.Bitmap;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.contacts.common.util.BitmapUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Tests for {@link com.android.contacts.common.util.BitmapUtil}.
+ */
+@SmallTest
+public class BitmapUtilTests extends AndroidTestCase {
+ public void testGetSmallerExtentFromBytes1() throws Exception {
+ assertEquals(100, BitmapUtil.getSmallerExtentFromBytes(createJpegRawData(100, 100)));
+ assertEquals(100, BitmapUtil.getSmallerExtentFromBytes(createPngRawData(100, 100)));
+ }
+
+ public void testGetSmallerExtentFromBytes2() throws Exception {
+ assertEquals(50, BitmapUtil.getSmallerExtentFromBytes(createJpegRawData(200, 50)));
+ assertEquals(50, BitmapUtil.getSmallerExtentFromBytes(createPngRawData(200, 50)));
+ }
+
+ public void testGetSmallerExtentFromBytes3() throws Exception {
+ assertEquals(40, BitmapUtil.getSmallerExtentFromBytes(createJpegRawData(40, 150)));
+ assertEquals(40, BitmapUtil.getSmallerExtentFromBytes(createPngRawData(40, 150)));
+ }
+
+ public void testFindOptimalSampleSizeExact() throws Exception {
+ assertEquals(1, BitmapUtil.findOptimalSampleSize(512, 512));
+ }
+
+ public void testFindOptimalSampleSizeBigger() throws Exception {
+ assertEquals(1, BitmapUtil.findOptimalSampleSize(512, 1024));
+ }
+
+ public void testFindOptimalSampleSizeSmaller1() throws Exception {
+ assertEquals(2, BitmapUtil.findOptimalSampleSize(512, 256));
+ }
+
+ public void testFindOptimalSampleSizeSmaller2() throws Exception {
+ assertEquals(2, BitmapUtil.findOptimalSampleSize(512, 230));
+ }
+
+ public void testFindOptimalSampleSizeSmaller3() throws Exception {
+ assertEquals(4, BitmapUtil.findOptimalSampleSize(512, 129));
+ }
+
+ public void testFindOptimalSampleSizeSmaller4() throws Exception {
+ assertEquals(4, BitmapUtil.findOptimalSampleSize(512, 128));
+ }
+
+ public void testFindOptimalSampleSizeUnknownOriginal() throws Exception {
+ assertEquals(1, BitmapUtil.findOptimalSampleSize(-1, 128));
+ }
+
+ public void testFindOptimalSampleSizeUnknownTarget() throws Exception {
+ assertEquals(1, BitmapUtil.findOptimalSampleSize(128, -1));
+ }
+
+ public void testDecodeWithSampleSize1() throws IOException {
+ assertBitmapSize(128, 64, BitmapUtil.decodeBitmapFromBytes(createJpegRawData(128, 64), 1));
+ assertBitmapSize(128, 64, BitmapUtil.decodeBitmapFromBytes(createPngRawData(128, 64), 1));
+ }
+
+ public void testDecodeWithSampleSize2() throws IOException {
+ assertBitmapSize(64, 32, BitmapUtil.decodeBitmapFromBytes(createJpegRawData(128, 64), 2));
+ assertBitmapSize(64, 32, BitmapUtil.decodeBitmapFromBytes(createPngRawData(128, 64), 2));
+ }
+
+ public void testDecodeWithSampleSize2a() throws IOException {
+ assertBitmapSize(25, 20, BitmapUtil.decodeBitmapFromBytes(createJpegRawData(50, 40), 2));
+ assertBitmapSize(25, 20, BitmapUtil.decodeBitmapFromBytes(createPngRawData(50, 40), 2));
+ }
+
+ public void testDecodeWithSampleSize4() throws IOException {
+ assertBitmapSize(32, 16, BitmapUtil.decodeBitmapFromBytes(createJpegRawData(128, 64), 4));
+ assertBitmapSize(32, 16, BitmapUtil.decodeBitmapFromBytes(createPngRawData(128, 64), 4));
+ }
+
+ private void assertBitmapSize(int expectedWidth, int expectedHeight, Bitmap bitmap) {
+ assertEquals(expectedWidth, bitmap.getWidth());
+ assertEquals(expectedHeight, bitmap.getHeight());
+ }
+
+ private byte[] createJpegRawData(int sourceWidth, int sourceHeight) throws IOException {
+ return createRawData(Bitmap.CompressFormat.JPEG, sourceWidth, sourceHeight);
+ }
+
+ private byte[] createPngRawData(int sourceWidth, int sourceHeight) throws IOException {
+ return createRawData(Bitmap.CompressFormat.PNG, sourceWidth, sourceHeight);
+ }
+
+ private byte[] createRawData(Bitmap.CompressFormat format, int sourceWidth,
+ int sourceHeight) throws IOException {
+ // Create a temp bitmap as our source
+ Bitmap b = Bitmap.createBitmap(sourceWidth, sourceHeight, Bitmap.Config.ARGB_8888);
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ b.compress(format, 50, outputStream);
+ final byte[] data = outputStream.toByteArray();
+ outputStream.close();
+ return data;
+ }
+}
diff --git a/tests/src/com/android/contacts/common/util/ContactDisplayUtilTests.java b/tests/src/com/android/contacts/common/util/ContactDisplayUtilTests.java
new file mode 100644
index 0000000..b4cd1ca
--- /dev/null
+++ b/tests/src/com/android/contacts/common/util/ContactDisplayUtilTests.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import static android.provider.ContactsContract.CommonDataKinds.Phone;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.preference.ContactsPreferences;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for (@link ContactDisplayUtils}
+ */
+@SmallTest
+public class ContactDisplayUtilTests extends AndroidTestCase {
+
+ private static final String NAME_PRIMARY = "Name Primary";
+ private static final String NAME_ALTERNATIVE = "Name Alternative";
+
+ @Mock private ContactsPreferences mContactsPreferences;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public void testIsCustomPhoneTypeReturnsTrue() {
+ assertTrue(ContactDisplayUtils.isCustomPhoneType(Phone.TYPE_CUSTOM));
+ assertTrue(ContactDisplayUtils.isCustomPhoneType(Phone.TYPE_ASSISTANT));
+ }
+
+ public void testIsCustomPhoneTypeReturnsFalse() {
+ assertFalse(ContactDisplayUtils.isCustomPhoneType(Phone.TYPE_HOME));
+ assertFalse(ContactDisplayUtils.isCustomPhoneType(Phone.TYPE_FAX_WORK));
+ assertFalse(ContactDisplayUtils.isCustomPhoneType(Phone.TYPE_MOBILE));
+ assertFalse(ContactDisplayUtils.isCustomPhoneType(Phone.TYPE_OTHER));
+ }
+
+ public void testGetLabelForCallOrSmsReturnsCustomLabel() {
+ final CharSequence smsResult = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_CUSTOM,
+ "expected sms label", ContactDisplayUtils.INTERACTION_SMS, getContext());
+ assertEquals("expected sms label", smsResult);
+
+ final CharSequence callResult = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_CUSTOM,
+ "expected call label", ContactDisplayUtils.INTERACTION_CALL, getContext());
+ assertEquals("expected call label", callResult);
+ }
+
+ public void testGetLabelForCallOrSmsReturnsCallLabels() {
+ CharSequence result = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_HOME, "",
+ ContactDisplayUtils.INTERACTION_CALL, getContext());
+ CharSequence expected = getContext().getResources().getText(R.string.call_home);
+ assertEquals(expected, result);
+
+ result = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_MOBILE, "",
+ ContactDisplayUtils.INTERACTION_CALL, getContext());
+ expected = getContext().getResources().getText(R.string.call_mobile);
+ assertEquals(expected, result);
+ }
+
+ public void testGetLabelForCallOrSmsReturnsSmsLabels() {
+ CharSequence result = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_HOME, "",
+ ContactDisplayUtils.INTERACTION_SMS, getContext());
+ CharSequence expected = getContext().getResources().getText(R.string.sms_home);
+ assertEquals(expected, result);
+
+ result = ContactDisplayUtils.getLabelForCallOrSms(Phone.TYPE_MOBILE, "",
+ ContactDisplayUtils.INTERACTION_SMS, getContext());
+ expected = getContext().getResources().getText(R.string.sms_mobile);
+ assertEquals(expected, result);
+ }
+
+ public void testGetPhoneLabelResourceIdReturnsOther() {
+ assertEquals(R.string.call_other, ContactDisplayUtils.getPhoneLabelResourceId(null));
+ }
+
+ public void testGetPhoneLabelResourceIdReturnsMatchHome() {
+ assertEquals(R.string.call_home, ContactDisplayUtils.getPhoneLabelResourceId(
+ Phone.TYPE_HOME));
+ }
+
+ public void testGetSmsLabelResourceIdReturnsOther() {
+ assertEquals(R.string.sms_other, ContactDisplayUtils.getSmsLabelResourceId(null));
+ }
+
+ public void testGetSmsLabelResourceIdReturnsMatchHome() {
+ assertEquals(R.string.sms_home, ContactDisplayUtils.getSmsLabelResourceId(Phone.TYPE_HOME));
+ }
+
+ public void testGetPreferredDisplayName_NullContactsPreferences() {
+ assertEquals(NAME_PRIMARY, ContactDisplayUtils.getPreferredDisplayName(NAME_PRIMARY,
+ NAME_ALTERNATIVE, null));
+ }
+
+ public void testGetPreferredDisplayName_NullContactsPreferences_NullAlternative() {
+ assertEquals(NAME_PRIMARY, ContactDisplayUtils.getPreferredDisplayName(NAME_PRIMARY, null,
+ null));
+ }
+
+ public void testGetPreferredDisplayName_NullContactsPreferences_NullPrimary() {
+ assertEquals(NAME_ALTERNATIVE, ContactDisplayUtils.getPreferredDisplayName(null,
+ NAME_ALTERNATIVE, null));
+ }
+
+ public void testGetPreferredDisplayName_NullContactsPreferences_BothNull() {
+ assertNull(ContactDisplayUtils.getPreferredDisplayName(null, null, null));
+ }
+
+ public void testGetPreferredDisplayName_EmptyAlternative() {
+ Mockito.when(mContactsPreferences.getDisplayOrder())
+ .thenReturn(ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE);
+ assertEquals(NAME_PRIMARY, ContactDisplayUtils.getPreferredDisplayName(NAME_PRIMARY, "",
+ mContactsPreferences));
+ }
+
+ public void testGetPreferredDisplayName_InvalidPreference() {
+ Mockito.when(mContactsPreferences.getDisplayOrder()).thenReturn(-1);
+ assertEquals(NAME_PRIMARY, ContactDisplayUtils.getPreferredDisplayName(NAME_PRIMARY,
+ NAME_ALTERNATIVE, mContactsPreferences));
+ }
+
+ public void testGetPreferredDisplayName_Primary() {
+ Mockito.when(mContactsPreferences.getDisplayOrder())
+ .thenReturn(ContactsPreferences.DISPLAY_ORDER_PRIMARY);
+ assertEquals(NAME_PRIMARY, ContactDisplayUtils.getPreferredDisplayName(NAME_PRIMARY,
+ NAME_ALTERNATIVE, mContactsPreferences));
+ }
+
+ public void testGetPreferredDisplayName_Alternative() {
+ Mockito.when(mContactsPreferences.getDisplayOrder())
+ .thenReturn(ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE);
+ assertEquals(NAME_ALTERNATIVE, ContactDisplayUtils.getPreferredDisplayName(NAME_PRIMARY,
+ NAME_ALTERNATIVE, mContactsPreferences));
+ }
+
+ public void testGetPreferredSortName_NullContactsPreferences() {
+ assertEquals(NAME_PRIMARY, ContactDisplayUtils.getPreferredSortName(NAME_PRIMARY,
+ NAME_ALTERNATIVE, null));
+ }
+
+ public void testGetPreferredSortName_NullContactsPreferences_NullAlternative() {
+ assertEquals(NAME_PRIMARY, ContactDisplayUtils.getPreferredSortName(NAME_PRIMARY, null,
+ null));
+ }
+
+ public void testGetPreferredSortName_NullContactsPreferences_NullPrimary() {
+ assertEquals(NAME_ALTERNATIVE, ContactDisplayUtils.getPreferredSortName(null,
+ NAME_ALTERNATIVE, null));
+ }
+
+ public void testGetPreferredSortName_NullContactsPreferences_BothNull() {
+ assertNull(ContactDisplayUtils.getPreferredSortName(null, null, null));
+ }
+
+ public void testGetPreferredSortName_EmptyAlternative() {
+ Mockito.when(mContactsPreferences.getSortOrder())
+ .thenReturn(ContactsPreferences.SORT_ORDER_ALTERNATIVE);
+ assertEquals(NAME_PRIMARY, ContactDisplayUtils.getPreferredSortName(NAME_PRIMARY, "",
+ mContactsPreferences));
+ }
+
+ public void testGetPreferredSortName_InvalidPreference() {
+ Mockito.when(mContactsPreferences.getSortOrder()).thenReturn(-1);
+ assertEquals(NAME_PRIMARY, ContactDisplayUtils.getPreferredSortName(NAME_PRIMARY,
+ NAME_ALTERNATIVE, mContactsPreferences));
+ }
+
+ public void testGetPreferredSortName_Primary() {
+ Mockito.when(mContactsPreferences.getSortOrder())
+ .thenReturn(ContactsPreferences.SORT_ORDER_PRIMARY);
+ assertEquals(NAME_PRIMARY, ContactDisplayUtils.getPreferredSortName(NAME_PRIMARY,
+ NAME_ALTERNATIVE, mContactsPreferences));
+ }
+
+ public void testGetPreferredSortName_Alternative() {
+ Mockito.when(mContactsPreferences.getSortOrder())
+ .thenReturn(ContactsPreferences.SORT_ORDER_ALTERNATIVE);
+ assertEquals(NAME_ALTERNATIVE, ContactDisplayUtils.getPreferredSortName(NAME_PRIMARY,
+ NAME_ALTERNATIVE, mContactsPreferences));
+ }
+}
diff --git a/tests/src/com/android/contacts/common/util/DateUtilTests.java b/tests/src/com/android/contacts/common/util/DateUtilTests.java
new file mode 100644
index 0000000..f460289
--- /dev/null
+++ b/tests/src/com/android/contacts/common/util/DateUtilTests.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 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.common.util;
+
+import junit.framework.TestCase;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.format.Time;
+
+/**
+ * Unit tests for {@link com.android.contacts.common.util.DateUtils}.
+ */
+@SmallTest
+public class DateUtilTests extends TestCase {
+
+ /**
+ * Test date differences which are in the same day.
+ */
+ public void testDayDiffNone() {
+ Time time = new Time();
+ long date1 = System.currentTimeMillis();
+ long date2 = System.currentTimeMillis() + android.text.format.DateUtils.HOUR_IN_MILLIS;
+ assertEquals(0, DateUtils.getDayDifference(time, date1, date2));
+ assertEquals(0, DateUtils.getDayDifference(time, date2, date1));
+ }
+
+ /**
+ * Test date differences which are a day apart.
+ */
+ public void testDayDiffOne() {
+ Time time = new Time();
+ long date1 = System.currentTimeMillis();
+ long date2 = date1 + android.text.format.DateUtils.DAY_IN_MILLIS;
+ assertEquals(1, DateUtils.getDayDifference(time, date1, date2));
+ assertEquals(1, DateUtils.getDayDifference(time, date2, date1));
+ }
+
+ /**
+ * Test date differences which are two days apart.
+ */
+ public void testDayDiffTwo() {
+ Time time = new Time();
+ long date1 = System.currentTimeMillis();
+ long date2 = date1 + 2*android.text.format.DateUtils.DAY_IN_MILLIS;
+ assertEquals(2, DateUtils.getDayDifference(time, date1, date2));
+ assertEquals(2, DateUtils.getDayDifference(time, date2, date1));
+ }
+}
diff --git a/tests/src/com/android/contacts/common/util/NameConverterTests.java b/tests/src/com/android/contacts/common/util/NameConverterTests.java
new file mode 100644
index 0000000..5a261eb
--- /dev/null
+++ b/tests/src/com/android/contacts/common/util/NameConverterTests.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 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.common.util;
+
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+
+import com.android.contacts.common.util.NameConverter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Tests for {@link NameConverter}.
+ */
+@SmallTest
+public class NameConverterTests extends AndroidTestCase {
+
+ public void testStructuredNameToDisplayName() {
+ Map<String, String> structuredName = new HashMap<String, String>();
+ structuredName.put(StructuredName.PREFIX, "Mr.");
+ structuredName.put(StructuredName.GIVEN_NAME, "John");
+ structuredName.put(StructuredName.MIDDLE_NAME, "Quincy");
+ structuredName.put(StructuredName.FAMILY_NAME, "Adams");
+ structuredName.put(StructuredName.SUFFIX, "Esquire");
+
+ assertEquals("Mr. John Quincy Adams, Esquire",
+ NameConverter.structuredNameToDisplayName(mContext, structuredName));
+
+ structuredName.remove(StructuredName.SUFFIX);
+ assertEquals("Mr. John Quincy Adams",
+ NameConverter.structuredNameToDisplayName(mContext, structuredName));
+
+ structuredName.remove(StructuredName.MIDDLE_NAME);
+ assertEquals("Mr. John Adams",
+ NameConverter.structuredNameToDisplayName(mContext, structuredName));
+ }
+
+ public void testDisplayNameToStructuredName() {
+ assertStructuredName("Mr. John Quincy Adams, Esquire",
+ "Mr.", "John", "Quincy", "Adams", "Esquire");
+ assertStructuredName("John Doe", null, "John", null, "Doe", null);
+ assertStructuredName("Ms. Jane Eyre", "Ms.", "Jane", null, "Eyre", null);
+ assertStructuredName("Dr Leo Spaceman, PhD", "Dr", "Leo", null, "Spaceman", "PhD");
+ }
+
+ /**
+ * Helper method to check whether a given display name parses out to the other parameters.
+ * @param displayName Display name to break into a structured name.
+ * @param prefix Expected prefix (null if not expected).
+ * @param givenName Expected given name (null if not expected).
+ * @param middleName Expected middle name (null if not expected).
+ * @param familyName Expected family name (null if not expected).
+ * @param suffix Expected suffix (null if not expected).
+ */
+ private void assertStructuredName(String displayName, String prefix,
+ String givenName, String middleName, String familyName, String suffix) {
+ Map<String, String> structuredName = NameConverter.displayNameToStructuredName(mContext,
+ displayName);
+ checkNameComponent(StructuredName.PREFIX, prefix, structuredName);
+ checkNameComponent(StructuredName.GIVEN_NAME, givenName, structuredName);
+ checkNameComponent(StructuredName.MIDDLE_NAME, middleName, structuredName);
+ checkNameComponent(StructuredName.FAMILY_NAME, familyName, structuredName);
+ checkNameComponent(StructuredName.SUFFIX, suffix, structuredName);
+ assertEquals(0, structuredName.size());
+ }
+
+ /**
+ * Checks that the given field and value are present in the structured name map (or not present
+ * if the given value is null). If the value is present and matches, the key is removed from
+ * the map - once all components of the name are checked, the map should be empty.
+ * @param field Field to check.
+ * @param value Expected value for the field (null if it is not expected to be populated).
+ * @param structuredName The map of structured field names to values.
+ */
+ private void checkNameComponent(String field, String value,
+ Map<String, String> structuredName) {
+ if (TextUtils.isEmpty(value)) {
+ assertNull(structuredName.get(field));
+ } else {
+ assertEquals(value, structuredName.get(field));
+ }
+ structuredName.remove(field);
+ }
+}
diff --git a/tests/src/com/android/contacts/common/util/SearchUtilTest.java b/tests/src/com/android/contacts/common/util/SearchUtilTest.java
new file mode 100644
index 0000000..3176a3c
--- /dev/null
+++ b/tests/src/com/android/contacts/common/util/SearchUtilTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2012 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.common.util;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link SearchUtil}.
+ */
+@SmallTest
+public class SearchUtilTest extends TestCase {
+
+ public void testFindMatchingLine() {
+ final String actual = "this is a long test string.\nWith potentially many lines.\n" +
+ "test@google.com\nhello\nblah\n'leading punc";
+
+ SearchUtil.MatchedLine matched = SearchUtil.findMatchingLine(actual, "poten");
+ assertEquals("With potentially many lines.", matched.line);
+ assertEquals(5, matched.startIndex);
+
+ // Full line match.
+ matched = SearchUtil.findMatchingLine(actual, "hello");
+ assertEquals("hello", matched.line);
+ assertEquals(0, matched.startIndex);
+
+ // First line match
+ matched = SearchUtil.findMatchingLine(actual, "this");
+ assertEquals("this is a long test string.", matched.line);
+ assertEquals(0, matched.startIndex);
+
+ // Last line match
+ matched = SearchUtil.findMatchingLine(actual, "punc");
+ assertEquals("'leading punc", matched.line);
+ assertEquals(9, matched.startIndex);
+ }
+
+ public void testContains() {
+ final String actual = "this is a long test string.\nWith potentially many lines.\n" +
+ "test@google.com\nhello\nblah\n'leading punc";
+ assertEquals(0, SearchUtil.contains(actual, "this"));
+ assertEquals(10, SearchUtil.contains(actual, "lon"));
+
+ assertEquals(1, SearchUtil.contains("'leading punc", "lead"));
+ assertEquals(9, SearchUtil.contains("'leading punc", "punc"));
+
+ }
+
+ public void testContainsNotFound() {
+ final String actual = "this is a long test string.\nWith potentially many lines.\n" +
+ "test@google.com\nhello\nblah\n'leading punc";
+
+ // Non-prefix
+ assertEquals(-1, SearchUtil.contains(actual, "ith"));
+ assertEquals(-1, SearchUtil.contains(actual, "ing"));
+
+ // Complete misses
+ assertEquals(-1, SearchUtil.contains(actual, "thisx"));
+ assertEquals(-1, SearchUtil.contains(actual, "manyx"));
+ assertEquals(-1, SearchUtil.contains(actual, "hellox"));
+
+ // Test for partial match of start of query to end of line
+ assertEquals(-1, SearchUtil.contains(actual, "punctual"));
+ }
+
+ public void testFindNextTokenStart() {
+ final String actual = "....hello.kitty";
+ // 012345678901234
+
+ // Find first token.
+ assertEquals(4, SearchUtil.findNextTokenStart(actual, 0));
+ assertEquals(4, SearchUtil.findNextTokenStart(actual, 1));
+ assertEquals(4, SearchUtil.findNextTokenStart(actual, 2));
+ assertEquals(4, SearchUtil.findNextTokenStart(actual, 3));
+
+ // Find second token.
+ assertEquals(10, SearchUtil.findNextTokenStart(actual, 4));
+ assertEquals(10, SearchUtil.findNextTokenStart(actual, 5));
+ assertEquals(10, SearchUtil.findNextTokenStart(actual, 6));
+ assertEquals(10, SearchUtil.findNextTokenStart(actual, 7));
+ assertEquals(10, SearchUtil.findNextTokenStart(actual, 8));
+ assertEquals(10, SearchUtil.findNextTokenStart(actual, 9));
+
+ // No token.
+ assertEquals(actual.length(), SearchUtil.findNextTokenStart(actual, 10));
+ assertEquals(actual.length(), SearchUtil.findNextTokenStart(actual, 11));
+ assertEquals(actual.length(), SearchUtil.findNextTokenStart(actual, 12));
+ assertEquals(actual.length(), SearchUtil.findNextTokenStart(actual, 13));
+ assertEquals(actual.length(), SearchUtil.findNextTokenStart(actual, 14));
+ }
+
+ public void testCleanStartAndEndOfSearchQuery() {
+ assertEquals("test", SearchUtil.cleanStartAndEndOfSearchQuery("...test..."));
+ assertEquals("test", SearchUtil.cleanStartAndEndOfSearchQuery(" test "));
+ assertEquals("test", SearchUtil.cleanStartAndEndOfSearchQuery(" ||test"));
+ assertEquals("test", SearchUtil.cleanStartAndEndOfSearchQuery("test.."));
+ }
+
+}
diff --git a/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java b/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java
index 4802b46..07ad722 100644
--- a/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java
@@ -15,12 +15,9 @@
*/
package com.android.contacts.interactions;
-import com.android.contacts.common.R;
-
import android.content.res.Configuration;
import android.content.res.Resources;
import android.test.AndroidTestCase;
-import android.text.format.DateUtils;
import java.util.Calendar;
import java.util.Locale;
@@ -80,54 +77,44 @@
getContext()));
}
- public void testFormatDateStringFromTimestamp_yesterday() {
- // Test yesterday and tomorrow (Yesterday or Tomorrow shown)
- calendar.add(Calendar.DAY_OF_YEAR, -1);
- assertEquals(getContext().getResources().getString(R.string.yesterday),
- ContactInteractionUtil.formatDateStringFromTimestamp(calendar.getTimeInMillis(),
- getContext()));
- }
-
- public void testFormatDateStringFromTimestamp_yesterdayLastYear() {
- // Set to non leap year
- calendar.set(Calendar.YEAR, 1999);
- calendar.set(Calendar.DAY_OF_YEAR, 365);
- long lastYear = calendar.getTimeInMillis();
- calendar.add(Calendar.DAY_OF_YEAR, 1);
-
- assertEquals(getContext().getResources().getString(R.string.yesterday),
- ContactInteractionUtil.formatDateStringFromTimestamp(lastYear,
- getContext(), calendar));
- }
-
- public void testFormatDateStringFromTimestamp_tomorrow() {
- calendar.add(Calendar.DAY_OF_YEAR, 1);
- assertEquals(getContext().getResources().getString(R.string.tomorrow),
- ContactInteractionUtil.formatDateStringFromTimestamp(calendar.getTimeInMillis(),
- getContext()));
- }
-
- public void testFormatDateStringFromTimestamp_tomorrowNewYear() {
- calendar.set(Calendar.DAY_OF_YEAR, 1);
- long thisYear = calendar.getTimeInMillis();
- calendar.add(Calendar.DAY_OF_YEAR, -1);
-
- assertEquals(getContext().getResources().getString(R.string.tomorrow),
- ContactInteractionUtil.formatDateStringFromTimestamp(thisYear,
- getContext(), calendar));
- }
-
public void testFormatDateStringFromTimestamp_other() {
// Test other (Month Date)
calendar.set(
/* year = */ 1991,
/* month = */ Calendar.MONTH,
- /* day = */ 11);
- assertEquals("March 11",
+ /* day = */ 11,
+ /* hourOfDay = */ 8,
+ /* minute = */ 8);
+ assertEquals("Monday, March 11, 1991, 8:08 AM",
ContactInteractionUtil.formatDateStringFromTimestamp(calendar.getTimeInMillis(),
getContext()));
}
+ public void testFormatDuration_zero() {
+ assertEquals("0 sec",
+ ContactInteractionUtil.formatDuration(0, getContext()));
+ }
+
+ public void testFormatDuration_minZeroSec() {
+ assertEquals("1 min 0 sec",
+ ContactInteractionUtil.formatDuration(60, getContext()));
+ }
+
+ public void testFormatDuration_minSec() {
+ assertEquals("30 min 9 sec",
+ ContactInteractionUtil.formatDuration(1809, getContext()));
+ }
+
+ public void testFormatDuration_hrZeroMinZeroSec() {
+ assertEquals("1 hr 0 min 0 sec",
+ ContactInteractionUtil.formatDuration(3600, getContext()));
+ }
+
+ public void testFormatDuration_hrMinSec() {
+ assertEquals("2 hr 44 min 36 sec",
+ ContactInteractionUtil.formatDuration(9876, getContext()));
+ }
+
private void setLocale(Locale locale) {
Locale.setDefault(locale);
Resources res = getContext().getResources();